{"data":{"post":{"fields":{"slug":"/complex-command-handler-in-javascript/","date":"2018-10-22"},"html":"<p>Recently I needed to carry out some complicated process in my Node.js side project. This process consisted of multiple steps and while some of them could be run in parallel some other required to be run in sequence. Here I will show the basic solution I came up with as it’s quite short and demonstrates the way of using both <code class=\"language-text\">Promise</code>s and <code class=\"language-text\">async</code>/<code class=\"language-text\">await</code>.</p>\n<p>I wanted to follow the <a href=\"https://en.wikipedia.org/wiki/Command_pattern\">Command design pattern</a> where Command object representing a single operation is provided with all the data required for carrying it out. Later such Command object is provided to a dedicated CommandHandler that would actually perform the task at hand, possibly making use of some external dependencies.</p>\n<p>In other words, I needed a piece of code that will execute some composite command that I would define upfront. This composite command would describe the whole process and would be composed of other composite commands (that would be handled recursively) or simple commands (that would have their dedicated command handlers provided as services). Let’s go through the process of building such a service.</p>\n<p>First, let’s prepare some classes that will represent our commands. We need two classes for it: one for the atomic command that will be provided to a dedicated CommandHandler, and one composite command for composing multiple commands (either atomic or composite) into a set that can be handled either in parallel or in sequence. Let’s call them SimpleCommand and CompositeCommand --- they will be quite basic.</p>\n<p>For the sake of simplicity we won’t require our atomic commands to describe any real operations --- we will provide them only with identifiers so that we can track if everything works fine:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">SimpleCommand</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>id <span class=\"token operator\">=</span> id<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>A composite command is also simple --- it needs to have a collection of nested commands and a flag that will indicate whether it’s possible to handle these nested commands in parallel, or whether they have to be run in sequence:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">CompositeCommand</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span>children<span class=\"token punctuation\">,</span> allowParallel <span class=\"token operator\">=</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>children <span class=\"token operator\">=</span> children<span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>allowParallel <span class=\"token operator\">=</span> allowParallel<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Since our simple commands are just for demo purposes we can handle them all with a single handler that will simply make each of them take some random time to complete. We will also include some <code class=\"language-text\">console.log</code> calls there that will show us when the handling of given command started and completed.</p>\n<p>We will expect the <code class=\"language-text\">handle</code> method to return a <code class=\"language-text\">Promise</code> that will be resolved when command has completed. To makes things simple we don’t care about any result (which also matches the default approach as when using Command design pattern we usually make an assumption that commands can be handled asynchronously, e.g. queued).</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">SimpleCommandHandler</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">handle</span><span class=\"token punctuation\">(</span>simpleCommand<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">const</span> delay <span class=\"token operator\">=</span> <span class=\"token number\">100</span> <span class=\"token operator\">+</span> <span class=\"token number\">100</span> <span class=\"token operator\">*</span> Math<span class=\"token punctuation\">.</span><span class=\"token function\">round</span><span class=\"token punctuation\">(</span><span class=\"token number\">20</span> <span class=\"token operator\">*</span> Math<span class=\"token punctuation\">.</span><span class=\"token function\">random</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>simpleCommand<span class=\"token punctuation\">.</span>id<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> - started, will take </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>delay<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> ms`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token keyword\">return</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Promise</span><span class=\"token punctuation\">(</span>resolve <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token function\">setTimeout</span><span class=\"token punctuation\">(</span>\n                <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n                    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>simpleCommand<span class=\"token punctuation\">.</span>id<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> - completed`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                    <span class=\"token function\">resolve</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\t\t\t\tdelay\n            <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Now let’s define a sample composite command that we would like to handle so that we better understand its data structure. We will have five main stages marked with letters from A to E.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> command <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">CompositeCommand</span><span class=\"token punctuation\">(</span>\n    <span class=\"token punctuation\">[</span>\n        <span class=\"token keyword\">new</span> <span class=\"token class-name\">CompositeCommand</span><span class=\"token punctuation\">(</span>\n            <span class=\"token punctuation\">[</span>\n                <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'A1'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'A2'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'A3'</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            <span class=\"token boolean\">false</span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token keyword\">new</span> <span class=\"token class-name\">CompositeCommand</span><span class=\"token punctuation\">(</span>\n            <span class=\"token punctuation\">[</span>\n                <span class=\"token keyword\">new</span> <span class=\"token class-name\">CompositeCommand</span><span class=\"token punctuation\">(</span>\n                    <span class=\"token punctuation\">[</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'B1'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'B2'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'B3'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'B4'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'B5'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'B6'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'B7'</span><span class=\"token punctuation\">)</span>\n                    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token boolean\">false</span>\n                <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                <span class=\"token keyword\">new</span> <span class=\"token class-name\">CompositeCommand</span><span class=\"token punctuation\">(</span>\n                    <span class=\"token punctuation\">[</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'C1'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'C2'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">CompositeCommand</span><span class=\"token punctuation\">(</span>\n                            <span class=\"token punctuation\">[</span>\n                                <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'C3a'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                                <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'C3b'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                                <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'C3c'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                                <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'C3d'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                                <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'C3e'</span><span class=\"token punctuation\">)</span>\n                            <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n                            <span class=\"token boolean\">true</span>\n                        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'C4'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'C5'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'C6'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token boolean\">false</span>\n                <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                <span class=\"token keyword\">new</span> <span class=\"token class-name\">CompositeCommand</span><span class=\"token punctuation\">(</span>\n                    <span class=\"token punctuation\">[</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'D1'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'D2'</span><span class=\"token punctuation\">)</span>\n                    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token boolean\">false</span>\n                <span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            <span class=\"token boolean\">true</span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token keyword\">new</span> <span class=\"token class-name\">CompositeCommand</span><span class=\"token punctuation\">(</span>\n            <span class=\"token punctuation\">[</span>\n                <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'E1'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'E2'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                <span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">(</span><span class=\"token string\">'E3'</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            <span class=\"token boolean\">false</span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token boolean\">false</span>\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>As you can see, stage A is to be executed first, then stages B, C, D in parallel; finally stage E should be handled. Each of these stages is composed from other commands which you can see on diagram below.</p>\n<p><img src=\"/img/complex-task.png\"></p>\n<p>Now we can start implementing <code class=\"language-text\">CompositeCommandHandler</code> that we will use to handle our <code class=\"language-text\">command</code>.  It will accept an instance of <code class=\"language-text\">SingleCommandHandler</code> as a constructor argument and will use it once it reaches <code class=\"language-text\">SimpleCommand</code> object.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">CompositeCommandHandler</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span>simpleCommandHandler<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>simpleCommandHandler <span class=\"token operator\">=</span> simpleCommandHandler<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token comment\">// More methods needed here.</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>We will now implement the main <code class=\"language-text\">handle</code> method that will accept either <code class=\"language-text\">SimpleCommand</code> or <code class=\"language-text\">CompositeCommand</code> object. If <code class=\"language-text\">SimpleCommand</code> is receiver it can simply use <code class=\"language-text\">SimpleCommandHandler</code> to handle it. Otherwise it will call one of the methods we will define later for handling commands in parallel or in sequence.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">CompositeCommandHandler</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Methods defined previously.</span>\n\n    <span class=\"token function\">handle</span><span class=\"token punctuation\">(</span>command<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>command <span class=\"token keyword\">instanceof</span> <span class=\"token class-name\">SimpleCommand</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>simpleCommandHandler<span class=\"token punctuation\">.</span><span class=\"token function\">handle</span><span class=\"token punctuation\">(</span>command<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>command <span class=\"token keyword\">instanceof</span> <span class=\"token class-name\">CompositeCommand</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>command<span class=\"token punctuation\">.</span>allowParallel<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">handleInParallel</span><span class=\"token punctuation\">(</span>command<span class=\"token punctuation\">.</span>children<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t        <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n\t            <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">handleInSequence</span><span class=\"token punctuation\">(</span>command<span class=\"token punctuation\">.</span>children<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">}</span>\n \n        <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Unknown class of command.'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token function\">handleInParallel</span><span class=\"token punctuation\">(</span>commands<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// To be defined.</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token function\">handleInSequence</span><span class=\"token punctuation\">(</span>commands<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// To be defined.</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The return value of our <code class=\"language-text\">handle</code> method is a <code class=\"language-text\">Promise</code> that will be resolved once a single command (in case of <code class=\"language-text\">SimpleCommand</code> is provided) or multiple commands are completed. We just need to check which kind of command was provided and --- for <code class=\"language-text\">CompositeCommand</code> --- whether they should be executed in parallel or in sequence. It’s easy to see that when we will be implementing <code class=\"language-text\">handleInParallel</code> and <code class=\"language-text\">handleInSequence</code> method we will be able to recursively call the <code class=\"language-text\">handle</code> method to execute each of commands provided to them, while these specialized methods will only be responsible for linking promises resulting from it in an appropriate way.</p>\n<p>For each of the remaining methods we will compare and contrast two approaches --- we will implement them with <code class=\"language-text\">Promise</code>s first and then we will compare it with a solution based on <code class=\"language-text\">async</code>/<code class=\"language-text\">await</code> syntactic sugar. If you’re not familiar with these please check related pages on MDN Web Docs: <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function\">async</a>, <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await\">await</a>, <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise\">Promise</a>.</p>\n<p>Let’s start with <code class=\"language-text\">handleInParallel</code> and <code class=\"language-text\">Promise</code>. Our method needs to return an instance of <code class=\"language-text\">Promise</code> that should be resolved once all provided commands are completed. To execute these commands in parallel we can call the <code class=\"language-text\">handle</code> method of <code class=\"language-text\">SimpleCommandHandler</code> for each of them. This way we’ll obtain a set of promises. When all of them are resolved we can resolve the promise that was our return value. Luckily we can use <code class=\"language-text\">Promise.all</code> method to easily obtain the composite promise we need to return.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">CompositeCommandHandler</span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token comment\">// Methods defined previously.</span>\n\n    <span class=\"token function\">handleInParallel</span><span class=\"token punctuation\">(</span>commands<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">const</span> promises <span class=\"token operator\">=</span> commands<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span>command <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">handle</span><span class=\"token punctuation\">(</span>command<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token keyword\">return</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">all</span><span class=\"token punctuation\">(</span>promises<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token function\">handleInSequence</span><span class=\"token punctuation\">(</span>commands<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// To be defined.</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>First, we map each element of <code class=\"language-text\">commands</code> to a <code class=\"language-text\">Promise</code> using the <code class=\"language-text\">handle</code> method recursively (as command can be either simple or composite and we’ve already implemented the logic of handling them there). Then this array of promisses is used as an argument for <code class=\"language-text\">Promise.all</code> which produces composite instance of <code class=\"language-text\">Promise</code> class that we need to return.</p>\n<p>We need only one more method to make our <code class=\"language-text\">CompositeCommandHandler</code> work and it’s <code class=\"language-text\">handleInSequence</code> Let’s try to use <code class=\"language-text\">Promise</code> again.</p>\n<p>What we need to do is to handle the first element of <code class=\"language-text\">commands</code> argument. Only when it is completed (e.g. promise resulting from handling it is resolved) we can handle the next element of <code class=\"language-text\">commands</code>. We should do so until all commands are handled and then we can use the last instance of <code class=\"language-text\">Promise</code> as our return value. Let’s express this with code then --- for the sake of simplicity we can assume that <code class=\"language-text\">commands</code> will never be an empty array.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">CompositeCommandHandler</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Methods defined previously.</span>\n\t\n    <span class=\"token function\">handleInSequence</span><span class=\"token punctuation\">(</span>commands<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">let</span> lastPromise <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">handle</span><span class=\"token punctuation\">(</span>commands<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> command <span class=\"token keyword\">of</span> commands<span class=\"token punctuation\">.</span><span class=\"token function\">slice</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            lastPromise <span class=\"token operator\">=</span> lastPromise<span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">handle</span><span class=\"token punctuation\">(</span>command<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        \n        <span class=\"token keyword\">return</span> lastPromise<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>In this example we don’t care about the result of handling each command and therefore we can simple chain promises using <code class=\"language-text\">then</code> callbacks that don’t require any arguments. We produce first promise outside of the <code class=\"language-text\">for ... of</code> loop and then for each subsequent command we add a <code class=\"language-text\">then</code> callback that will handle the net element of <code class=\"language-text\">commands</code> and return resulting promise. This creates a new promise that we store in the <code class=\"language-text\">lastPromise</code> variable and use it in next loop. The final value of <code class=\"language-text\">lastPromise</code> is used as return value as it will be resolved when the last command is completed.</p>\n<p>Since we’ve implemented all methods that were needed, let’s now run our sample composite command.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> handler <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">CompositeCommandHandler</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">SimpleCommandHandler</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Running commands.'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\nhandler\n    <span class=\"token punctuation\">.</span><span class=\"token function\">handle</span><span class=\"token punctuation\">(</span>command<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>\n        <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'All commands completed.'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        error <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Some commands failed'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>Now let’s run it in command line.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">node ./complex-command-handler.js </code></pre></div>\n<p>It will give different output each time as delays are random, but the order of commands execution will be correct.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Running commands.\nA1 - started, will take 1100 ms\nA1 - completed\nA2 - started, will take 1300 ms\nA2 - completed\nA3 - started, will take 1100 ms\nA3 - completed\nB1 - started, will take 1900 ms\nC1 - started, will take 300 ms\nD1 - started, will take 1300 ms\nC1 - completed\nC2 - started, will take 2100 ms\nD1 - completed\nD2 - started, will take 2100 ms\nB1 - completed\nB2 - started, will take 1900 ms\nC2 - completed\nC3a - started, will take 1100 ms\nC3b - started, will take 1200 ms\nC3c - started, will take 1800 ms\nC3d - started, will take 1300 ms\nC3e - started, will take 1300 ms\nD2 - completed\nC3a - completed\nC3b - completed\nC3d - completed\nC3e - completed\nB2 - completed\nB3 - started, will take 1800 ms\nC3c - completed\nC4 - started, will take 700 ms\nC4 - completed\nC5 - started, will take 400 ms\nC5 - completed\nC6 - started, will take 500 ms\nB3 - completed\nB4 - started, will take 2000 ms\nC6 - completed\nB4 - completed\nB5 - started, will take 1500 ms\nB5 - completed\nB6 - started, will take 1300 ms\nB6 - completed\nB7 - started, will take 900 ms\nB7 - completed\nE1 - started, will take 1000 ms\nE1 - completed\nE2 - started, will take 1300 ms\nE2 - completed\nE3 - started, will take 300 ms\nE3 - completed\nAll commands completed.</code></pre></div>\n<p>So our code already does what it was expected to do, but the implementation of <code class=\"language-text\">handleInSequence</code> method is not as readable as we would like. Let’s check if using <code class=\"language-text\">async</code>/<code class=\"language-text\">await</code> syntactic sugar could improve this.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">async</span> <span class=\"token function\">handleInSequence</span><span class=\"token punctuation\">(</span>commands<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> command <span class=\"token keyword\">of</span> commands<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">await</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">handle</span><span class=\"token punctuation\">(</span>command<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Wow, that’s something! As you can see we only need to loop through provided commands and <code class=\"language-text\">await</code> for each <code class=\"language-text\">handle</code> call. This will pause the execution of this method until this nested promise is resolved. (Of course, it won’t stop the execution of other callbacks that are in motion as this would beat the purpose of using an asynchronous tool like Node.js). Since we don’t care about results returned we can end our method without explicitly returning any value --- defining this method as <code class=\"language-text\">async</code> will automatically wrap it’s result value with <code class=\"language-text\">Promise</code> object that caller method expects to receive!</p>\n<p>We can clearly see that this implementation is better and easier to analyze, so let’s use it instead of the previous one.</p>\n<p>Since it went so well for <code class=\"language-text\">handleInSequence</code>, let’s now get back to implementing <code class=\"language-text\">handleInParallel</code> but this time using <code class=\"language-text\">async</code>/<code class=\"language-text\">await</code> approach. In this case it doesn’t result in an easy to read the code, though.</p>\n<p>First, we can wonder why we can’t simply call the <code class=\"language-text\">handle</code> method for each command inside a <code class=\"language-text\">for ... of</code> loop and <code class=\"language-text\">await</code> for them to be resolved? The problem is that this will not yield the expected result --- note that we’ve already used this approach when we implemented <code class=\"language-text\">handleInSequence</code> method! The reason is that <code class=\"language-text\">await</code> would pause the execution of our method for every single <code class=\"language-text\">handle</code> call. This would prevent handling of subsequent commands for even getting started and instead of being executed in parallel they would be run in sequence.</p>\n<p>Therefore we need to initiate handling of all commands first, and only then <code class=\"language-text\">await</code> for their results.    </p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">async</span> <span class=\"token function\">handleInParallel</span><span class=\"token punctuation\">(</span>commands<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> promises <span class=\"token operator\">=</span> commands<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>command<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">return</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">handle</span><span class=\"token punctuation\">(</span>command<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n\n    <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> promise <span class=\"token keyword\">of</span> promises<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">await</span> promise<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>We are still calling our variable <code class=\"language-text\">promises</code> as this is what is really returned from <code class=\"language-text\">handle</code> and what is used by <code class=\"language-text\">async</code>/<code class=\"language-text\">await</code> syntax internally.</p>\n<p>You will probably agree that in this case the solution with <code class=\"language-text\">Promise</code> was much more readable. Like we described above we are first mapping set of commands to set of promises by calling the <code class=\"language-text\">handle</code> method recursively and therefore they run in sequence. (We don’t have a need for <code class=\"language-text\">map</code> callback function to be declared as <code class=\"language-text\">async</code> as it doesn’t need to <code class=\"language-text\">await</code> for anything --- it receives <code class=\"language-text\">Promise</code> object from the <code class=\"language-text\">handle</code> method and it is expected to return one.</p>\n<p>After mapping all commands to promises we need to wait for all of them to be resolved. Now it’s time to use <code class=\"language-text\">await</code> in a <code class=\"language-text\">for ... of</code> loop --- there may be some commands that will take longer to be completed, but even if this loop will be temporarily blocked by one of them them the remaining commands will already be in progress.</p>\n<p>The order of awaiting doesn’t matter here --- if some command runs quicker and completes before we use <code class=\"language-text\">await</code> on it there will be no need to pause the execution of our method.</p>\n<p>Finally, we don’t need to return anything as <code class=\"language-text\">Promise</code> object is automatically created when we declare our method as <code class=\"language-text\">async</code>.</p>\n<p>Now we’re done - we have compared implementations using <code class=\"language-text\">Promise</code> and <code class=\"language-text\">async</code>/<code class=\"language-text\">await</code>. In our case handling commands in parallel was more readable when we used <code class=\"language-text\">Promise</code>, while for running in sequence  <code class=\"language-text\">async</code>/<code class=\"language-text\">await</code> solution seems more suitable.</p>\n<p>This demonstrates that for writing succinct and readable code it’s important to know both these techniques, to understand their inner workings so that we can use either of them depending on a task at hand.</p>","frontmatter":{"title":"Complex command handler in JavaScript","subTitle":"Comparison of using Promise and async/await","postAuthor":"Mariusz Bąk (malef)","cover":"/img/js.jpg"}},"tags":{"group":[{"name":"$OSTYPE","totalCount":1,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}}]},{"name":".env","totalCount":1,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}}]},{"name":".nvrmc","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"AUTO_INCREMENT","totalCount":1,"edges":[{"node":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}}]},{"name":"Angular","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Command","totalCount":1,"edges":[{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}}]},{"name":"DQL","totalCount":2,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}},{"node":{"fields":{"slug":"/mysql-decimal-format/"}}}]},{"name":"Data Transfer Object","totalCount":1,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}}]},{"name":"Docker","totalCount":3,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}},{"node":{"fields":{"slug":"/quick-import-of-mysql-database-dump/"}}},{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Docker Compose","totalCount":3,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}},{"node":{"fields":{"slug":"/quick-import-of-mysql-database-dump/"}}},{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Doctrine","totalCount":2,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}},{"node":{"fields":{"slug":"/mysql-decimal-format/"}}}]},{"name":"Doctrine NEW","totalCount":1,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}}]},{"name":"ES7","totalCount":1,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}}]},{"name":"Elastica","totalCount":1,"edges":[{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}}]},{"name":"Elasticsearch","totalCount":1,"edges":[{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}}]},{"name":"Elasticsearch script","totalCount":1,"edges":[{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}}]},{"name":"Express","totalCount":1,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}}]},{"name":"Git","totalCount":2,"edges":[{"node":{"fields":{"slug":"/git-not-detecting-renames-quick-workarounds/"}}},{"node":{"fields":{"slug":"/git-reverting-branch-removal/"}}}]},{"name":"Git renamed","totalCount":1,"edges":[{"node":{"fields":{"slug":"/git-not-detecting-renames-quick-workarounds/"}}}]},{"name":"HTTP","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-does-slack-communicate-with-spotify/"}}}]},{"name":"JavaScript","totalCount":3,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}},{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}},{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"Kafka","totalCount":1,"edges":[{"node":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}}]},{"name":"MySQL","totalCount":4,"edges":[{"node":{"fields":{"slug":"/mysql-decimal-format/"}}},{"node":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}},{"node":{"fields":{"slug":"/php-with-mysql-8/"}}},{"node":{"fields":{"slug":"/quick-import-of-mysql-database-dump/"}}}]},{"name":"MySQL 8","totalCount":1,"edges":[{"node":{"fields":{"slug":"/php-with-mysql-8/"}}}]},{"name":"Node.js","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"ORM","totalCount":1,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}}]},{"name":"PDO","totalCount":1,"edges":[{"node":{"fields":{"slug":"/php-with-mysql-8/"}}}]},{"name":"PDO_MYSQL","totalCount":1,"edges":[{"node":{"fields":{"slug":"/php-with-mysql-8/"}}}]},{"name":"PHP","totalCount":6,"edges":[{"node":{"fields":{"slug":"/doctrine-new-dql-operator-and-objects/"}}},{"node":{"fields":{"slug":"/mysql-decimal-format/"}}},{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}},{"node":{"fields":{"slug":"/php-with-mysql-8/"}}},{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}},{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"Phing","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"Promise","totalCount":1,"edges":[{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}}]},{"name":"Python","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"React","totalCount":2,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}},{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Redux","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"Redux store","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"SPA","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"Slack","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-does-slack-communicate-with-spotify/"}}}]},{"name":"Spotify","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-does-slack-communicate-with-spotify/"}}}]},{"name":"Travis","totalCount":2,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}},{"node":{"fields":{"slug":"/elasticsearch-script-unknown-field-source-parser-not-found/"}}}]},{"name":"Vue","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"XDEBUG_CONFIG","totalCount":1,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}}]},{"name":"XDebug","totalCount":1,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}}]},{"name":"ai","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"amazon","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"apple-watch","totalCount":1,"edges":[{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"asp.net core","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"async","totalCount":2,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}},{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}}]},{"name":"autocomplete","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"await","totalCount":2,"edges":[{"node":{"fields":{"slug":"/async-await-with-express/"}}},{"node":{"fields":{"slug":"/complex-command-handler-in-javascript/"}}}]},{"name":"aws","totalCount":3,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}},{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}},{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"aws.cli","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"bash","totalCount":2,"edges":[{"node":{"fields":{"slug":"/cross-system-xdebug-docker-compose-setup/"}}},{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"bitbucket","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"blazor","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"build","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"builder pattern","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"c#","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"ci","totalCount":1,"edges":[{"node":{"fields":{"slug":"/unresolved-check-from-travis-on-github-pull-request/"}}}]},{"name":"claude-code","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"cognito","totalCount":1,"edges":[{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"colors","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"continuous integration","totalCount":1,"edges":[{"node":{"fields":{"slug":"/unresolved-check-from-travis-on-github-pull-request/"}}}]},{"name":"decimal","totalCount":1,"edges":[{"node":{"fields":{"slug":"/mysql-decimal-format/"}}}]},{"name":"docker","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"ec2","totalCount":1,"edges":[{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}}]},{"name":"environment","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"equals","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"flysystem","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"front-end","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"git","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"git commit","totalCount":1,"edges":[{"node":{"fields":{"slug":"/git-not-detecting-renames-quick-workarounds/"}}}]},{"name":"git reflog","totalCount":1,"edges":[{"node":{"fields":{"slug":"/git-reverting-branch-removal/"}}}]},{"name":"git status","totalCount":1,"edges":[{"node":{"fields":{"slug":"/git-not-detecting-renames-quick-workarounds/"}}}]},{"name":"github","totalCount":3,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}},{"node":{"fields":{"slug":"/unresolved-check-from-travis-on-github-pull-request/"}}},{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"guide","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"hashcode","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"hibernate","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"java","totalCount":2,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}},{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"java.time","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"jaxb","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"jdk8","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"jpa","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"maven","totalCount":1,"edges":[{"node":{"fields":{"slug":"/make-jaxb-great-again/"}}}]},{"name":"middleware","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"mono","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"multi-stage","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"naming","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"networking","totalCount":1,"edges":[{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}}]},{"name":"ntp","totalCount":1,"edges":[{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}}]},{"name":"nvm","totalCount":1,"edges":[{"node":{"fields":{"slug":"/travis-problematic-python-and-node/"}}}]},{"name":"persistence","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"port 4381","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-does-slack-communicate-with-spotify/"}}}]},{"name":"pr","totalCount":1,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}}]},{"name":"production","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"project","totalCount":1,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}}]},{"name":"pull","totalCount":1,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}}]},{"name":"qa","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"razor","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"reducer","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}}]},{"name":"regex","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-write-a-phing-target-autocomplete-bash-script/"}}}]},{"name":"repo","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"repository","totalCount":1,"edges":[{"node":{"fields":{"slug":"/how-to-quickly-remove-merged-remote-branches/"}}}]},{"name":"s3","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"sass","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"setup","totalCount":1,"edges":[{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"skills","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"styles","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"symfony","totalCount":1,"edges":[{"node":{"fields":{"slug":"/minio-as-s3-replacement-in-development-and-beyond/"}}}]},{"name":"templates","totalCount":1,"edges":[{"node":{"fields":{"slug":"/pull-request-templates-on-github/"}}}]},{"name":"test-automation","totalCount":1,"edges":[{"node":{"fields":{"slug":"/weekly-ai-bites-last-manual-gap-qa-testing/"}}}]},{"name":"transaction","totalCount":1,"edges":[{"node":{"fields":{"slug":"/is-mysql-autoincrement-really-monotonic/"}}}]},{"name":"travis","totalCount":1,"edges":[{"node":{"fields":{"slug":"/unresolved-check-from-travis-on-github-pull-request/"}}}]},{"name":"tutorial","totalCount":2,"edges":[{"node":{"fields":{"slug":"/how-to-implement-redux-in-react/"}}},{"node":{"fields":{"slug":"/Dev-and-prod-ready-Docker-setup-for-SPA-app/"}}}]},{"name":"ubuntu","totalCount":1,"edges":[{"node":{"fields":{"slug":"/time-out-of-sync-in-aws-ec2/"}}}]},{"name":"unsupported","totalCount":1,"edges":[{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"uuid","totalCount":1,"edges":[{"node":{"fields":{"slug":"/jpa-and-uuid/"}}}]},{"name":"variables","totalCount":1,"edges":[{"node":{"fields":{"slug":"/naming-sass-color-variables/"}}}]},{"name":"wasm","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]},{"name":"watchos","totalCount":1,"edges":[{"node":{"fields":{"slug":"/aws-cognito-without-library/"}}}]},{"name":"web","totalCount":1,"edges":[{"node":{"fields":{"slug":"/net-in-my-browser/"}}}]}]},"author":{"id":"37bda159-ff45-50c9-aeba-18326b7ca66b","childMarkdownRemark":{"html":"<p><strong>XSolve</strong> We are Agile Software House focused on PHP/Symfony, #JavaScript, #Java and #Mobile (iOS, Android, Windows Phone) #Inc5000 European company in 2018.\n<br>\n<a href=\"https://xsolve.software\">xsolve.software</a></p>"}},"footnote":{"id":"b4474c9b-7be6-5f34-866a-cdfffa885bce","childMarkdownRemark":{"html":"<ul>\n<li>From <a href=\"https://www.boldare.com/\">Boldare</a></li>\n<li>with <a href=\"https://github.com/greglobinski/gatsby-starter-personal-blog/\">Gatsby starter</a></li>\n<li>delivered by <a href=\"https://www.netlify.com/\">Netlify</a></li>\n</ul>"}},"site":{"siteMetadata":{"facebook":{"appId":""}}}},"pageContext":{"slug":"/complex-command-handler-in-javascript/"}}