All this async code without decent locking primitives is leading to a rabbit hole of race conditions... It doesn't matter that it's all single threaded if all your function calls may or may not block and run a bunch of other code in the meantime, mutating all kinds of state. I feel like JavaScript developers of the 2020's are going to relearn the same things the C programmers of the 1990's learn, just a few levels of…
Data races are impossible in JavaScript because it's single-threaded. Race conditions are possible in any language that can do anything asynchronous, which is basically all of them. But the general benefit you get from JS being single-threaded is the fact that any given callback is transactional. No other code will ever come in and mutate state between two regular lines of JavaScript code. Achieving this is pretty mu…
Granted, my practical experience is limited. I haven't really run into any of these kinds of situations outside of database work in Node, and there you've got the major benefit of transactions to do the locking for you, so the async JavaScript code doesn't have to particularly care and can yield whenever it wants.
For me, the real benefit of await / async so far has mostly just been about improving code flow. Promises were already an excellent solution to the async problem, but their syntax for all but the most trivial example is something only a mother could love. async/await makes the code structure suddenly not necessarily look like callback hell, and in a lot of cases it's much more compact and easier to read. It greatly improves the chances that when I come back to it a month later, I won't have to reach back into the past and slap myself for writing that monstrosity. :)