Have you ever noticed different state or ui show up when refreshing the page that you didn’t expect? Does it seems like no matter how hard you try you can never get consistent steps to reproduce a bug? Then you may have a race condition.
A race condition or race hazard is the behavior of an electronic, software or other system where the output is dependent on the sequence or timing of other uncontrollable events. It becomes a bug when events do not happen in the order the programmer intended.
Hopefully this makes sense. Breaking it down to you have two or more time dependent tasks that depend on each other. The race condition happens when your expected “race” is won by an unexpected task. Let’s look at an example. All of these samples are written in ES2015 and can run in the latest version of FireFox.
This is a simplified example and I hope you never write code like this, but this is what is going on in your app.
Imagine if we didn’t have the setTimeouts in
calculateZ. Step by step we would get the value of
x, and then calculate
z. No problem. The issue is when we introduce the async function
setTimeout with random delay times. This makes the code to where we can’t just rely on the first
setTimeout resolving first. Sometimes it will sometimes it won’t, so race condition! The value of
z will depend on who wins the
So how can we fix this? Since we can’t predict who will finish first we can chain the calls together to ensure we get
y first before moving on to getting
x and finally calculating
That works, but what happens if this was an ajax call that took a large amount of time? We have effectively doubled the time to calculate
z because of the chained calls. This is where promises can run both calls in parallel improving our performance and removing the race condition.
Don’t worry if you haven’t see promises before. They are a great tool and now part of the language. I would suggest studying up on them.
Hopefully, this article clears up what a race condition is and how to solve them. In my personal experience race conditions never appear right away, they tend to sneak into the codebase when adding new features, modules, or data stores that rely on existing code for state. Once identified they can be solved by applying some form of chaining.