First, What is a Race Condition?
A race condition is an undesirable situation that occurs when a device or system attempts to perform two or more operations at the same time, but because of the nature of the device or system, the operations must be done in the proper sequence to be done correctly.
A simple example of race condition would be one light source that is attached to two different light controllers. When we target the light source with two simultaneous actions - one switches on, and the other switches off. The uncertain end result whether the light source is on or off.
JavaScript asynchronization can't be in parallel as JavaScript executes on a single thread, but it works with concurrency.
What is the difference between concurrency and parallelism?

If we run this program on a computer with a single CPU core, the OS would be switching between the two threads, allowing one thread to run at a time.
If we run this program on a computer with a multi-core CPU then we would be able to run the two threads in parallel - side by side at the exact same time.

But a race condition can occur with any async operations whether it happens with concurrency or parallelism
Let’s have a clearer scenario which can produce a race condition in JavaScript.
Let’s assume we have a scenario like this one:
- We have a map
- We want to show some information related to the location of the user
- Every time a user is moving on the map we fetch for the data
- We are smart and we even debounce the fetches for 0.5 seconds
- The data is returned after 5 seconds (we are on a slow network).
Now let’s think of the next case:
- The user opens the map
- The first fetch request is fired
- After 2 seconds, the user moves on the map again, because the user felt like the user found something interesting
- After another 0.5 seconds, another fetch is fired
Now, if for some reason for the first fetch it took 5 seconds to return and for the second fetch it took 1 second to return (the network signal got better or the fetch/computation size is much smaller or we got not so busy server for the second time), what will happen now?
We have this method to fetch the data and update it via updateState
.
fetch(url)
.then(data => data.json())
.then(data => updateState(data));
In this case, some weird async bug will happen. We look at area2, but see the items of area1.
Some solutions…
So you ask me what can I do?
You can save the last request and cancel it on the next one. For the moment of writing this article, fetch doesn’t have a cancellation API. But for the sake of the argument here is a code with setTimeout
:
if (this.lastRequest) {
clearTimeout(this.lastRequest);
}
this.lastRequest = setTimeout(() => {
updateState([1,2,3]);
this.lastRequest = null;
}, 5000);
You can create a session object on every new request and save it, and on response check, the saved one is still the same as the one you have:
const currentSession ={};
this.lastSession = currentSession;
fetch(url)
.then(data => data.json())
.then(items =>{
if (this.lastSession !== currentSession) {
return;
}
updateState(items);
}).catch(error =>{
if (this.lastSession !== currentSession){
return;
}
setError(error);
});
Resources.
Is there Race Condition in JavaScript: Yes and No
What is the difference between concurrency and parallelism?
How to avoid async race conditions in JavaScript