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?
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.
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.
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.
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.
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:
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With