{"id":1525,"date":"2016-08-05T10:35:18","date_gmt":"2016-08-05T14:35:18","guid":{"rendered":"https:\/\/lowtek.ca\/roo\/?p=1525"},"modified":"2016-08-05T10:38:07","modified_gmt":"2016-08-05T14:38:07","slug":"javascript-and-the-single-threaded-lie","status":"publish","type":"post","link":"https:\/\/lowtek.ca\/roo\/2016\/javascript-and-the-single-threaded-lie\/","title":{"rendered":"JavaScript and the Single Threaded Lie"},"content":{"rendered":"<blockquote><p>JavaScript is single threaded<\/p><\/blockquote>\n<p>Yes, <strong>but<\/strong>.. it is also heavily asynchronous.\u00a0Since my <a href=\"https:\/\/github.com\/ibmruntimes\/v8ppc\/commits?author=andrewlow\">experience porting Node.js to new platforms<\/a>, it&#8217;s turned into one of my go to languages for hacking web apps. Unfortunately I still fall into the async trap.<\/p>\n<p>Let&#8217;s look at some code:<\/p>\n<pre class=\"lang:default decode:true\">function myFunction(value, callback) {\r\n  setTimeout(function () {\r\n    console.log('Processing value: ' + value);\r\n    callback();\r\n  }, 2000);\r\n}\r\n\r\nvar array = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];\r\n\r\nfor (var i = 0; i &lt; array.length; i++) {\r\n  var item = array[i];\r\n  myFunction(item, function () {\r\n    console.log('Done processing value: ' + item);\r\n  });\r\n}\r\n<\/pre>\n<p class=\"p1\">And here is the output of the code if we run it:<\/p>\n<pre class=\"lang:default decode:true \">$ node bad.js \r\nProcessing value: 1\r\nDone processing value: 9\r\nProcessing value: 2\r\nDone processing value: 9\r\nProcessing value: 3\r\nDone processing value: 9\r\nProcessing value: 4\r\nDone processing value: 9\r\nProcessing value: 5\r\nDone processing value: 9\r\nProcessing value: 6\r\nDone processing value: 9\r\nProcessing value: 7\r\nDone processing value: 9\r\nProcessing value: 8\r\nDone processing value: 9\r\nProcessing value: 9\r\nDone processing value: 9\r\n<\/pre>\n<p>Now, in this example &#8211; it&#8217;s pretty clear what is causing the issue. The <code>setTimeout()<\/code> is doing a delay of 2 seconds. This is an async call, so the <code>for<\/code> loop has completed it&#8217;s entire cycle before any of the callbacks get a chance to run. Timing issues also make things more confusing\u00a0if things sometimes work since you can&#8217;t guarantee the order of asynchronous functions.<\/p>\n<p>The trap for me, is when the code is more complex and it isn&#8217;t obvious to see that there is an async call in the way. Also, my brain keeps telling me that for each iteration through the loop, I (think I&#8217;m) creating a new variable (<code>item<\/code>) and that should provide correct isolation for the state.<\/p>\n<p>There are two simple solutions to this problem.<\/p>\n<h4>Solution 1 &#8211; use the call stack:<\/h4>\n<pre class=\"lang:default decode:true \">function myFunction(value, callback) {\r\n  setTimeout(function () {\r\n    console.log('Processing value: ' + value);\r\n    callback();\r\n  }, 2000);\r\n}\r\n\r\nfunction helper(item) {\r\n  myFunction(item, function () {\r\n    console.log('Done processing value: ' + item);\r\n  });\r\n}\r\n\r\nvar array = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];\r\n\r\nfor (var i = 0; i &lt; array.length; i++) {\r\n  var item = array[i];\r\n  helper(item);\r\n}\r\n<\/pre>\n<p>Move the async call <code>myFunction<\/code> into a helper and pass the value to it. This moves it from being a local variable to one on the stack (as a parameter to helper).<\/p>\n<h4>Solution 2 &#8211; have the callback give the value back:<\/h4>\n<pre class=\"lang:default decode:true \">function myFunction(value, callback) {\r\n  setTimeout(function () {\r\n    console.log('Processing value: ' + value);\r\n    callback(value);\r\n  }, 2000);\r\n}\r\n\r\nvar array = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];\r\n\r\nfor (var i = 0; i &lt; array.length; i++) {\r\n  var item = array[i];\r\n  myFunction(item, function (value) {\r\n    console.log('Done processing value: ' + value);\r\n  });\r\n}\r\n<\/pre>\n<p>To be honest, solution 2 is just another call stack approach &#8211; but it&#8217;s a different enough pattern to be a second solution.<\/p>\n<p>The output of both good solutions looks like:<\/p>\n<pre class=\"lang:default decode:true \">$ node good.js \r\nProcessing value: 1\r\nDone processing value: 1\r\nProcessing value: 2\r\nDone processing value: 2\r\nProcessing value: 3\r\nDone processing value: 3\r\nProcessing value: 4\r\nDone processing value: 4\r\nProcessing value: 5\r\nDone processing value: 5\r\nProcessing value: 6\r\nDone processing value: 6\r\nProcessing value: 7\r\nDone processing value: 7\r\nProcessing value: 8\r\nDone processing value: 8\r\nProcessing value: 9\r\nDone processing value: 9\r\n<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>JavaScript is single threaded Yes, but.. it is also heavily asynchronous.\u00a0Since my experience porting Node.js to new platforms, it&#8217;s turned into one of my go to languages for hacking web apps. Unfortunately I still fall into the async trap. Let&#8217;s look at some code: function myFunction(value, callback) { setTimeout(function () { console.log(&#8216;Processing value: &#8216; + &hellip; <a href=\"https:\/\/lowtek.ca\/roo\/2016\/javascript-and-the-single-threaded-lie\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;JavaScript and the Single Threaded Lie&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-1525","post","type-post","status-publish","format-standard","hentry","category-computing"],"_links":{"self":[{"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/posts\/1525","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/comments?post=1525"}],"version-history":[{"count":5,"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/posts\/1525\/revisions"}],"predecessor-version":[{"id":1530,"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/posts\/1525\/revisions\/1530"}],"wp:attachment":[{"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/media?parent=1525"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/categories?post=1525"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/tags?post=1525"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}