Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

Suppose I load some Flash movie that I know at some point in the future will call window.flashReady and will set window.flashReadyTriggered = true.

Now I have a block of code that I want to have executed when the Flash is ready. I want it to execute it immediately if window.flashReady has already been called and I want to put it as the callback in window.flashReady if it has not yet been called. The naive approach is this:

if(window.flashReadyTriggered) {   block(); } else {   window.flashReady = block; } 

So the concern I have based on this is that the expression in the if condition is evaluated to false, but then before block() can be executed, window.flashReady is triggered by the external Flash. Consequently, block is never called.

Is there a better design pattern to accomplish the higher level goal I'm going for (e.g., manually calling the flashReady callback)? If not, am I safe, or are there other things I should do?

like image 405
Steven Avatar asked Aug 30 '11 04:08

Steven


People also ask

Are race conditions possible in JavaScript?

A single-threaded event loop like the one used by JavaScript and Node. js, makes it somewhat harder to have race conditions, but, SPOILER ALERT: race conditions are still possible! In this article, we will explore the topic of race conditions in Node. js.

Is asynchronous JavaScript important?

Asynchronous programming makes it possible to express waiting for long-running actions without freezing the program during these actions. JavaScript environments typically implement this style of programming using callbacks, functions that are called when the actions complete.

How can you avoid race condition when you are dealing with threads in Java?

Race conditions can be avoided by proper thread synchronization in critical sections. Thread synchronization can be achieved using a synchronized block of Java code. Thread synchronization can also be achieved using other synchronization constructs like locks or atomic variables like java.

How asynchronous events are handled in JavaScript?

An async function can contain an await expression, that pauses the execution of the function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value. You can think of a Promise in JavaScript as the equivalent of Java's Future or C# 's Task.


2 Answers

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.

like image 69
jfriend00 Avatar answered Oct 21 '22 08:10

jfriend00


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?

like image 42
kay Avatar answered Oct 21 '22 06:10

kay