{"id":1460,"date":"2014-03-04T22:01:20","date_gmt":"2014-03-05T03:01:20","guid":{"rendered":"http:\/\/unitstep.net\/?p=1460"},"modified":"2015-10-02T08:13:31","modified_gmt":"2015-10-02T13:13:31","slug":"javascript-single-threadedness-and-timers","status":"publish","type":"post","link":"https:\/\/unitstep.net\/blog\/2014\/03\/04\/javascript-single-threadedness-and-timers\/","title":{"rendered":"JavaScript single-threadedness and timers"},"content":{"rendered":"

If you’re coming from a programming language that has support for multithreading and concurrency, (such as Java) then understanding the flow of asynchronous events in JavaScript such as timers can be a bit confusing.<\/p>\n

However, once you understand the single-threaded nature of most JavaScript, things may actually becoming easier as you don’t have to worry about parallel access to non-local variables.<\/p>\n

Let’s take a look at how JavaScript executes when a function is passed to window.setTimeout()<\/code>.<\/p>\n

<\/p>\n

Multithreading<\/h2>\n

As anyone who’s done a fair amount of Java will know, it’s fairly easy to easy to spawn a new Thread, usually by submitting a new Runnable<\/code> to a Thread Pool or ExecutorService<\/code>, or less frequently, by directly creating an instance of Thread<\/code> and calling start()<\/code>. Since this post isn’t about Java, I won’t talk anymore about it, other than to say when you do this, you have created\/spawned another thread – so you now have at least two threads: The one you just created and the original\/main one that created the second thread.<\/p>\n

The first thing you’ll realize is that with multiple threads executing, by default there is no defined order to how they will execute. So, if I spawned two threads, one printing \"a\"<\/code> to stdout<\/code> repeatedly and one printing \"b\"<\/code> to stdout<\/code>, there is no guarantee of the order the letters would appear on screen and furthermore, it would likely vary from execution to execution of the program.<\/p>\n

This leads to the need for synchronization and locks on concurrent code in order to maintain a certain level of ordering in how concurrent code operates. Is the same true for JavaScript?<\/p>\n

JavaScript Timers<\/h2>\n

I will focus my example on the setTimeout()<\/a><\/code> timer, though the same principle I’l be demonstrating holds for other asynchronous events.<\/p>\n

What will be the value of output<\/code> after the following code has executed?<\/p>\n

var output = '';\r\nvar iterations = 10000000;\r\nsetTimeout(function() {\r\n  for (var i = 0; i < iterations; ++i) {\r\n    output += 'a';\r\n  }\r\n}, 100);\r\nsetTimeout(function() {\r\n  for (var i = 0; i < iterations; ++i) {\r\n    output += 'b';\r\n  }\r\n}, 100);<\/code><\/pre>\n

In this example, it would seem that we have kicked off the execution of two long-running functions at approximately the same time and both are modifying\/mutating a global\/shared variable.<\/p>\n

If this example involved multithreaded execution, the value of output<\/code> would have several alternations between the letters ‘a’ and ‘b’.<\/p>\n

Conversely, if output<\/code> consisted of a solid block of ‘a’ followed by a solid block of ‘b’, we could conclude that it was likely the first function executed completely before the second function was allowed to execute.<\/p>\n

In my brief tests in Chrome 33.0 and Firefox 27.0 this was the case: A solid block of ‘a’, followed by a solid block of ‘b’. (You can see the full example\/test in this gist<\/a>.)<\/p>\n

This would seem to indicate that there is only a single thread of execution in JavaScript, as the execution of one function completely blocked the execution<\/strong> of another.<\/p>\n

A little deeper<\/h2>\n

What’s really going on is that the calls to setTimeout<\/code> are asynchronous. This means they return (almost) immediately and instead just queue up an event<\/strong> to invoke the passed-in function later. This means that the function that writes ‘a’ to output<\/code> will execute before the function that outputs ‘b’. <\/p>\n

How the queue works is likely implementation-specific, but when an event is read off the queue and processed, it blocks<\/strong> while that event\/function is being executed. <\/p>\n

This behaviour doesn’t just apply for JavaScript timers like setTimeout\/setInterval<\/code> but for all asynchronous event handling in JavaScript. <\/p>\n

This is probably a key point: Asynchronous does not mean parallel!<\/strong> In the case of JavaScript, the concurrency is actually accomplished through this sort of context-switching, rather than having separate threads that actually execute\/run in in parallel\/at the same time.<\/p>\n

Web Workers<\/h2>\n

One important caveat: The above discussion did not involve Web Workers<\/a>, which is an API that does allow you to explicitly create separate threads<\/em> of processing in JavaScript. However, you must explicitly spawn these new threads and they can only communicate with the main thread through the use of specific APIs\/event handlers.<\/p>\n

By default, variables in the main thread aren’t shared with the worker threads. I suspect this was done to avoid problematic concurrent data-access issues.<\/p>\n

However, the Web Workers API does not affect how events such as setTimeout<\/code> work – everything above still holds.<\/p>\n

References<\/h3>\n
    \n
  1. How JavaScript Timers Work<\/a><\/li>\n
  2. Minimum\/maximum delay and timeout nesting<\/a><\/li>\n
  3. Introduction to HTML5 Web Workers: The JavaScript Multi-threading Approach<\/a><\/li>\n
  4. JavaScript’s Strange Threaded Nature<\/a><\/li>\n<\/ol>","protected":false},"excerpt":{"rendered":"

    If you’re coming from a programming language that has support for multithreading and concurrency, (such as Java) then understanding the flow of asynchronous events in JavaScript such as timers can be a bit confusing. However, once you understand the single-threaded nature of most JavaScript, things may actually becoming easier as you don’t have to worry […]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[4,137],"tags":[],"_links":{"self":[{"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/posts\/1460"}],"collection":[{"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/comments?post=1460"}],"version-history":[{"count":22,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/posts\/1460\/revisions"}],"predecessor-version":[{"id":1660,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/posts\/1460\/revisions\/1660"}],"wp:attachment":[{"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/media?parent=1460"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/categories?post=1460"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unitstep.net\/wp-json\/wp\/v2\/tags?post=1460"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}