Tuesday, May 14, 2024
115
rated 0 times [  122] [ 7]  / answers: 1 / hits: 7146  / 2 Years ago, tue, august 2, 2022, 12:00:00

I am aware JavaScript is single-threaded and technically can’t have race conditions, but it supposedly can have some uncertainty because of async and the event loop. Here’s an oversimplified example:


class TestClass {
// ...

async a(returnsValue) {
this.value = await returnsValue()
}
b() {
this.value.mutatingMethod()
return this.value
}
async c(val) {
await this.a(val)
// do more stuff
await otherFunction(this.b())
}
}

Assume that b() relies on this.value not having been changed since the call to a(), and c(val) is being called many times in quick succession from multiple different places in the program. Could this create a data race where this.value changes between calls to a() and b()?


For reference, I have preemptively fixed my issue with a mutex, but I’ve been questioning whether there was an issue to begin with.


More From » asynchronous

 Answers
4

Yes, race conditions can and do occur in JS as well. Just because it is single-threaded it doesn't mean race conditions can't happen (although they are rarer). JavaScript indeed is single-threaded but it is also asynchronous: a logical sequence of instructions is often divided into smaller chunks executed at different times. This makes interleaving possible, and hence race conditions arise.




For the simple example consider...


var x = 1;

async function foo() {
var y = x;
await delay(100); // whatever async here
x = y+1;
}

...which is the classical example of the non-atomic increment adapted to JavaScript's asynchronous world.


Now compare the following "parallel" execution:


await Promise.all([foo(), foo(), foo()]);
console.log(x); // prints 2

...with the "sequential" one:


await foo();
await foo();
await foo();
console.log(x); // prints 4

Note that the results are different, i.e. foo() is not "async safe".




Even in JS you sometimes have to use "async mutexes". And your example might be one of those situations, depending on what happens in between (e.g. if some asynchronous call occurs). Without an asynchronous call in do more stuff it looks like mutation occurs in a single block of code (bounded by asynchronous calls, but no asynchronous call inside to allow interleaving), and should be OK I think. Note that in your example the assignment in a is after await, while b is called before the final await.


[#45] Friday, July 8, 2022, 2 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
mariamiyanab

Total Points: 75
Total Questions: 102
Total Answers: 92

Location: British Indian Ocean Territory
Member since Tue, Feb 22, 2022
2 Years ago
mariamiyanab questions
Wed, Dec 15, 21, 00:00, 2 Years ago
Tue, Aug 3, 21, 00:00, 3 Years ago
Fri, Apr 3, 20, 00:00, 4 Years ago
Fri, Feb 28, 20, 00:00, 4 Years ago
;