News for hackers. Stuff that matters.
Re:V8 adds support for top-level await by pseudoramble on Tuesday September 24, 2019 @07:21PM (#21065759)
> 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.

Can you elaborate a bit more on this? I'm unsure about how locking in a single-threaded environment would work. And how would it really differ from async/await or promises which can handle race conditions already?

One area where the lack-of locking primitives does worry me is the use of shared mutable memory. I've never used these techniques in JS, but if I remember right one can now do something like this:

1. Create a shared memory array

2. Spawn several workers which do work on shared arrays

3. Pass a reference to the array to each worker and let them run.

This seems like an area where we could start to see these problems start appearing. There's a module related to atomic operations [1] but there is no language-level enforcement of using it. There could be good reasons why this isn't worrying but I just don't happen to know that off hand.

[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

Re:V8 adds support for top-level await by shanemhansen on Tuesday September 24, 2019 @07:28PM (#21065831)
In javascript anywhere you see await, you've introduced an explicit scheduling point. There are cases where even in a single threaded env you want to "wait" until some other async process is complete. To use one of the old school examples:

    function transfer(amount, acct1, acct2) {
        var current_balance = await acc1.balance()
        if current_balance > amount {
            await acct1.sub(amount)
            await acct2.add(amount)
        }
    }
Now what happens if you get multiple calls to transfer? What you want is probably something like:

    function transfer(amount, acct1, acct2) {
         await acct1.Lock()
         ....
         await acct1.UnLock()
    }
Re:V8 adds support for top-level await by hombre_fatal on Tuesday September 24, 2019 @08:32PM (#21066315)
I don't think it really makes sense to essentially say "Javascript is rife with race conditions like any other language" just because yes, you still need to use transactions when using a database.
Re:V8 adds support for top-level await by vidarh on Tuesday September 24, 2019 @10:17PM (#21066927)
You're reading too much into the example. Your 'database' can be your frontend js state. There is nothing in the example that limits the problem to backend development.
Re:V8 adds support for top-level await by jeswin on Tuesday September 24, 2019 @11:02PM (#21067191)
Yeah but the impact of race conditions on front-end code (which is always single user) is minimal; unlike the backend where it's catastrophic and not fixable by refreshing the page.
Re:V8 adds support for top-level await by vidarh on Wednesday September 25, 2019 @03:43AM (#21068660)
It is fixable by refreshing the page if there are no race conditions in the front-end.

If anything getting this right on the front-end is often extra problematic because of the high cost of round-tripping state to the server.

Re:V8 adds support for top-level await by olalonde on Wednesday September 25, 2019 @02:26AM (#21068228)
In that case, the code would be sync and there wouldn't be a "race condition".
Re:V8 adds support for top-level await by vidarh on Wednesday September 25, 2019 @03:45AM (#21068670)
I just the other day had to step in to deal with a race condition in a frontend caused by improperly handling async API requests.

It's dangerous to assume that just because JS has a single main thread that you don't need to think about sequencing of operations and locking.

Re:V8 adds support for top-level await by olalonde on Wednesday September 25, 2019 @06:57AM (#21069490)
While writing async code can indeed be challenging, I just disagree with the idea that JavaScript is lacking good "locking primitives":

> All this async code without decent locking primitives is leading to a rabbit hole of race conditions...

No, it's not. Here's a lock:

   let lock = Promise.resolve()
   // ...
   lock = lock.then(() => { /* critical section */ })
For the rare instances where more complex async flow control is required, there are a bunch of libraries for that (e.g. async[0], p-queue[1], etc.).

[0] https://caolan.github.io/async/v3/docs.html

[1] https://github.com/sindresorhus/p-queue

Re:V8 adds support for top-level await by pseudoramble on Tuesday September 24, 2019 @07:54PM (#21066047)
Good point! I hadn't thought of it this way since it often doesn't come up as often in my experiences with front end stuff.

To lay out one example as clearly as I can: suppose you had two calls to transfer with the same args.

* The 2nd call to `await acc1.balance()` was very quick beating the 1st call

* The `current_balance` is greater than `amount` and so it runs `await acct1.sub(amount)`

* Before that can finish, the 1st call to `balance()` returns with the old balance before subtraction begins.

* Now another transfer is initiated with the incorrect amount.

If `amount` is larger than `current balance` you've got an issue on your hand.

I believe one could implement a mechanism around this using a set of booleans/ints for each account and managing the call to `transfer` with each one of those. But that's the point - we could have primitives to do that.

By the way, there is a particular issue with this specific example. The `transfer` function signature must be marked as `async`. You would need to add this to make it run properly.

Re:V8 adds support for top-level await by blacksoil on Tuesday September 24, 2019 @09:39PM (#21066718)
Good example. I think this should be handled by whatever data store is being used, though. In case of SQL, transaction.
Re:V8 adds support for top-level await by asoo on Wednesday September 25, 2019 @03:02AM (#21068422)
You'd need to lock both accounts... but even then. Doing any kind of accounting operations without being atomic, transactional or idempotent is just wrong. Even with single call - acct2.add() could fail and you're left with broken state. If this is in-memory state then you don't need asyncs at all. If it's not, Locks just give you false sense of safety.
Re:V8 adds support for top-level await by trust07007707 on Tuesday September 24, 2019 @07:22PM (#21065773)
There is an Atomics API for that...