Do I need to be concerned with race conditions with asynchronous Javascript?

All Javascript event handler scripts are handled from one master event queue system. This means that event handlers run one at a time and one runs until completion before the next one that's ready to go starts running. As such, there are none of the typical race conditions in Javascript that one would see in a multithreaded language where multiple threads of the language can be running at once (or time sliced) and create real-time conflict for access to variables.

Any individual thread of execution in javascript will run to completion before the next one starts. That's how Javascript works. An event is pulled from the event queue and then code starts running to handle that event. That code runs by itself until it returns control to the system where the system will then pull the next event from the event queue and run that code until it returns control back to the system.

Thus the typical race conditions that are caused by two threads of execution going at the same time do not happen in Javascript.

This includes all forms of Javascript events including: user events (mouse, keys, etc..), timer events, network events (ajax callbacks), etc...

The only place you can actually do multi-threading in Javascript is with the HTML5 Web Workers or Worker Threads (in node.js), but they are very isolated from regular javascript (they can only communicate with regular javascript via message passing) and cannot manipulate the DOM at all and must have their own scripts and namespace, etc...


While I would not technically call this a race condition, there are situations in Javascript because of some of its asynchronous operations where you may have two or more asynchronous operations in flight at the same time (not actually executing Javascript, but the underlying asynchronous operation is running native code at the same time) and it may be unpredictable when each operation will complete relative to the others. This creates an uncertainty of timing which (if the relative timing of the operations is important to your code) creates something you have to manually code for. You may need to sequence the operations so one runs and you literally wait for it to complete before starting the next one. Or, you may start all three operations and then have some code that collects all three results and when they are all ready, then your code proceeds.

In modern Javascript, promises are generally used to manage these types of asynchronous operations.

So, if you had three asynchronous operations that each return a promise (like reading from a database, fetching a request from another server, etc...), you could manually sequence then like this:

a().then(b).then(c).then(result => {
    // result here
}).catch(err => {
    // error here
});

Or, if you wanted them all to run together (all in flight at the same time) and just know when they were all done, you could do:

Promise.all([a(), b(), c()])..then(results => {
    // results here
}).catch(err => {
    // error here
});

While I would not call these race conditions, they are in the same general family of designing your code to control indeterminate sequencing.


There is one special case that can occur in some situations in the browser. It's not really a race condition, but if you're using lots of global variables with temporary state, it could be something to be aware of. When your own code causes another event to occur, the browser will sometimes call that event handler synchronously rather than waiting until the current thread of execution is done. An example of this is:

  1. click
  2. the click event handler changes focus to another field
  3. that other field has an event handler for onfocus
  4. browser calls the onfocus event handler immediately
  5. onfocus event handler runs
  6. the rest of the click event handler runs (after the .focus() call)

This isn't technically a race condition because it's 100% known when the onfocus event handler will execute (during the .focus() call). But, it can create a situation where one event handler runs while another is in the middle of execution.


JavaScript is single threaded. There are no race conditions.

When there is no more code to execute at your current "instruction pointer", the "thread" "passes the baton", and a queued window.setTimeout or event handler may execute its code.

You will get better understanding for Javascript's single-threading approach reading node.js's design ideas.

Further reading: Why doesn't JavaScript support multithreading?

Tags:

Javascript