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.
You can read more about it here
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 is
let lightbulb = 'white'; syncChangeToRed(lightbulb); synChangeToBlue(lightbulb);
They will execute from top down order, so the same lightbulb will change to red first and then blue.
But suppose you have two asynchronous functions that try to change the same lightbulb, here's where it gets funky:
let lightbulb = 'white'; asyncChangeToRed(lightbulb); asyncChangeToBlue(lightbulb);
The returned time of each async function is not known. The part where async function done running in heap and handed over to queue is unknown and so whether asyncChangeToRed or asyncChangeToBlue to be executed first is undetermined.
As you can see the diagram, the race can only happen inside the heap, but when it's handed over to the queue, they are executed in ordered sequence.
Here are a few scenarios for you to think about:
If you fire asyncChangeToRed() and asyncChangeToBlue() from the same network, even if they spend the same amount of time in heap, because asyncChangeToRed() was fired first, it will be handed over to queue first.
It is deterministic, so no race condition.
If you fire asyncChangeToRed() on a low speed network, and asyncChangeToBlue() on a fast speed network, because asyncChangeToBlue returned faster from heap, it will be handed over to queue first hence executed first. The change is still deterministic because the speed of the network is known, so no race condition.
Now a more theoretical case if asyncChangeToRed() is fired on a x speed network vs. asyncChangeToBlue() on a y speed network separately at the same time, because x and y are unknown, the only way for a race condition to happen is if x === y.