News for hackers. Stuff that matters.
Re:V8 adds support for top-level await by _bxg1 on Tuesday September 24, 2019 @07:17PM (#21065728)
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 much the whole point of locking mechanisms, so under normal circumstances they aren't necessary for JS.

That said, when you use async/await instead of promises or callbacks, things do change because two sequential lines of code are no longer two truly sequential instructions. You're muddying the most fundamental metaphor of code syntax. That's why I personally don't like async/await syntax, although I get why people want it.

Re:V8 adds support for top-level await by zeta0134 on Wednesday September 25, 2019 @03:02AM (#21068420)
Ehh, I get where you're coming from, but await is at least explicit about it. Did you promise.then()? Did you call this function by putting an await in front of it? You yielded on purpose. If you need to keep hold of a resource on either side of that explicit action, either don't use either of those constructs, do but write a locking mechanism, or stop and think long and hard about why the lock is necessary.

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. :)

Re:V8 adds support for top-level await by gregmac on Tuesday September 24, 2019 @07:47PM (#21065995)
> two sequential lines of code are no longer two truly sequential instructions

I've done a lot of async/await and I really can't think of any situations where this has been a concern for me. If you're mutating state in method calls without explicitly passing it around, that might be an issue but that's a deeper design issue IMHO.

Re:V8 adds support for top-level await by PetahNZ on Tuesday September 24, 2019 @07:54PM (#21066055)
One use case I often find is a caching layer between JS and a HTTP call. If there are 2 calls to a non cached endpoint, the HTTP will fire off twice before caching the result. You can work around this by returning the first promise from the cache, but this is essentially a mutex. Having locking primitives would solve this and require less boilerplate code.
Re:V8 adds support for top-level await by tiglionabbit on Tuesday September 24, 2019 @11:46PM (#21067417)
Caching the promise is a perfectly good solution. Locks aren't needed.
Re:V8 adds support for top-level await by kbenson on Tuesday September 24, 2019 @08:31PM (#21066310)
Seems like you should be able to build a lock mechanism fairly simply with async/await, but I agree, it would be nice if it was a built in primitive. It does feel a little silly to implement a lock function when the engine much be using one to support its async functionality in the first place, so you're introducing a lot of inefficiency.
Re:V8 adds support for top-level await by Arelius on Tuesday September 24, 2019 @10:21PM (#21066952)
I don't think it's true that the engine must be using a mutex to support it's async functionality. Or that it is true that an OS mutex will be any more efficient than alternative solutions.

A mutex really can only exist to serialize async code. If you want it serialized that likely means that code shouldn't be async in the first place.

Re:V8 adds support for top-level await by kbenson on Wednesday September 25, 2019 @01:01AM (#21067744)
You're right that it may not be required for the async functionality (especially since lock-free schedulers exist, and the engine is basically a single processor scheduler for processes). I do think it's likely in use other places though, just because it's much easier to write correct code with one.
Re:V8 adds support for top-level await by matharmin on Wednesday September 25, 2019 @02:53AM (#21068386)
Implementing a mutex is very simple and efficient in JavaScript - probably much lower overhead than the Promises itself.
Re:V8 adds support for top-level await by jnbiche on Tuesday September 24, 2019 @11:17PM (#21067271)
You write this boilerplate to avoid one extra non-cached HTTP call on a (browser?) client? Am I understanding correctly?
Re:V8 adds support for top-level await by londons_explore on Wednesday September 25, 2019 @03:37AM (#21068631)
One extra call could be a multi-megabyte video chunk, or the code flow might mean this case always occurs, potentially hundreds of times before the promise resolves.
Re:V8 adds support for top-level await by matharmin on Wednesday September 25, 2019 @02:56AM (#21068395)
It's really not a lot of boilerplate - once you have the small utility function, it can be one additional line of code.
Re:V8 adds support for top-level await by random314 on Wednesday September 25, 2019 @11:56AM (#21071993)
When your program is single threaded, a simple boolean flag variable can act as a mutex, you don't need a mutex for this.

Mutexes are for situations where flag variables can change state between your instructions to check and set a flag. This can only happen in multithreaded or interrupt driven code.

Re:V8 adds support for top-level await by Arelius on Tuesday September 24, 2019 @10:18PM (#21066936)
Do you really want to block all of your http calls on the result of the prior call in the off-chance that they might share a result just so you can only cache the results and not the promises?

The reason we don't have a mutex in javascript is that there are better solutions to the problems it solves.

Re:V8 adds support for top-level await by hombre_fatal on Tuesday September 24, 2019 @11:03PM (#21067196)
Maybe I don't understand your response, but a map of promises to handle parallel in-flight requests for the same resource (which the grandparent pitched) is basically the most elegant yet simple solution to this common problem.

I don't really see how it's a mutex though, you're just returning the same promise to multiple requests. It's far simpler and doesn't use a locking construct.

Re:V8 adds support for top-level await by inglor on Wednesday September 25, 2019 @02:47AM (#21068349)
A promise is a lock in that resolving it is the 'release' and awaiting it is `acquire`.

For example:

``` let release; const acquire = new Promise(resolve => release = resolve);

(async () => {

  await acquire;
  // use here
  release(); // now others can use it
})(); ```

This is a bit different because multiple people can await the lock here so it's like a "one time multicast mutex" making it more akin to condition variables.

That said - thinking about it as a mutex is a really backwards way in my opinion.

Re:V8 adds support for top-level await by nine_k on Tuesday September 24, 2019 @08:28PM (#21066285)
I think it's worth stopping to think in terms of "sequential lines of code". Even at CPU level, "sequential" instructions aren't, for a decade or so, to say nothing of xplicitly async code.

One should think in terms of a dataflow graph, where data-independent nodes can run in any order, or in parallel. One should explicitly think about ordering of effects, and be explicit about effects in general. (Hence the rise of popularity of FP.)

Re:V8 adds support for top-level await by cellularmitosis on Tuesday September 24, 2019 @11:17PM (#21067272)
> Even at CPU level, "sequential" instructions aren't

Within the context of the argument you are making, this is disingenuous. There's a big pile of transistors which determine whether it is safe to reorder those instructions.

Re:V8 adds support for top-level await by nine_k on Wednesday September 25, 2019 @12:20AM (#21067566)
Thar same pile of transistors, with a thick layer of software, determines whether it's safe to proceed a coroutine.

    const foo = async () {
      const ice = await freeze(water);
      const wCream = await whip(cream);
      const base = await pour(liquor, ice);
      const cocktail = await put(base, wCream);
      return cocktail.serve();
    }
In the above fragment, `freeze` and `whip` may run in any order or in parallel, you don't get to choose. Still `pour` never runs before `freeze` (though it can complete before `whip`), and `put` can only run last. This is because the above is syntactic sugar, and the dataflow graph gets encoded in the promises graph, with `.then` clauses giving an unequivocal dependency order where applicable.

Same in CPU: two loads can run in either order or in parallel, but an ADD that takes the result of both of them will only run when they both complete.

Re:V8 adds support for top-level await by esprehn on Wednesday September 25, 2019 @12:45AM (#21067676)
Is there a bug in your example? You await freeze before calling whip. They can't run in any order or in parallel and must complete sequentially. pour also cannot complete before whip since whip is being awaited.

That example is:

    const foo = async () =>
      freeze(water)
        .then(ice => whip(cream)
          .then(wCream => pour(liquor, ice)
            .then(base => put(base, cream)
              .then(cocktail => cocktail.serve()))));
Re:V8 adds support for top-level await by nine_k on Wednesday September 25, 2019 @10:29AM (#21071106)
Thanks. I stand corrected.
Re:V8 adds support for top-level await by derangedHorse on Wednesday September 25, 2019 @08:57AM (#21070278)
Maybe there’s a misunderstanding with how async/await works...
Re:V8 adds support for top-level await by nine_k on Wednesday September 25, 2019 @10:31AM (#21071128)
Apparently so — thank you!
Re:V8 adds support for top-level await by chrisweekly on Tuesday September 24, 2019 @08:59PM (#21066493)
>"be explicit about effects in general. (Hence the rise of popularity of FP.)"

Yes - the benefits of pure functions in particular are increasingly evident.

Re:V8 adds support for top-level await by ihuman on Tuesday September 24, 2019 @08:32PM (#21066321)
> when you use async/await instead of promises or callbacks, things do change because two sequential lines of code are no longer two truly sequential instructions

I thought async/await was just syntactic sugar for promises?

Re:V8 adds support for top-level await by matharmin on Wednesday September 25, 2019 @02:59AM (#21068403)
Yes. I think what is meant here, is that two sequential lines with `await` in them are no longer sequential instructions, and other code may execute in between them.

If you were using promises or callbacks it would be the same, except that it won't appear like two sequential lines anymore.

Re:V8 adds support for top-level await by _bxg1 on Wednesday September 25, 2019 @12:49AM (#21067696)
It is; but in my experience that fact can make it harder to see what's truly going on.
Re:V8 adds support for top-level await by h8hawk on Tuesday September 24, 2019 @09:56PM (#21066815)
No it's not. async/await's semantic is similar to coroutines, and is implemented by them.
Re:V8 adds support for top-level await by ihuman on Tuesday September 24, 2019 @10:57PM (#21067162)
Are you sure? From what I can find, async [0] causes a function to a return a promise, which then returns the result. Await [1] takes a promise, and waits for it to either be resolved or rejected.

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

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

Re:V8 adds support for top-level await by matt-attack on Tuesday September 24, 2019 @11:46PM (#21067414)
> and waits for it

Yes but that doesn’t mean other lines of code can’t be executing while waiting. The waiting isn’t truly blocking the entire application. Plenty of other things can be happening.

Re:V8 adds support for top-level await by nemetroid on Wednesday September 25, 2019 @07:33AM (#21069681)
Sure, but the next line of the function awaiting the result can't execute while waiting.
Re:V8 adds support for top-level await by h8hawk on Wednesday September 25, 2019 @12:35AM (#21067639)
from your first link: "... , async/await is similar to combining generators and promises."
Re:V8 adds support for top-level await by s_tec on Wednesday September 25, 2019 @02:02AM (#21068093)
It is true that async functions work similarly to the coroutines found in other languages, and that some transpilers convert async functions into Javascript generator functions under the hood. However, these are both implementation details.

On the flip side, there is a Javascript transpiler called nodent which directly converts async functions into the corresponding `Promise.then` calls, with no generators in sight. This transpiler actually generates smaller & faster output than the standard generator-based approaches, since the async/await semantics map more directly to promises.

In other words, async functions really are semantic sugar for promises, even if they have some similarities to coroutines / generators.

To try it yourself, just go to http://nodent.mailed.me.uk/ , check the "spec compliant" option, and look at the generated output.

Re:V8 adds support for top-level await by gitgud on Wednesday September 25, 2019 @01:16AM (#21067836)
Maybe provide some evidence of this, I've also understood them as syntactic sugar for Promises.

Although I have found that babel does seem to transpile them differently to Promises

Re:V8 adds support for top-level await by burtonator on Tuesday September 24, 2019 @08:13PM (#21066179)
You're sort of right but it depends on the races and the data structures. If you depend on a remote function and ordering is important lots of problems can happen.

I've definitely needed more locking primitives and ordering but it's mostly for remote code.

There are also a ton of bugs that can happen with memory allocation.

For example if you do 50 async and they all come back and once and try to all allocate memory and then perform some action at the end you can have too many in flight and then use too much memory.

It's not really threaded but you can run into similar problems.

I've done 10+ years of core JVM threading with raw threads and softare transactional memory datastructures and CAS operations and my experience there helps a ton.

Async is definitely not just 'free'

Re:V8 adds support for top-level await by tudorconstantin on Tuesday September 24, 2019 @10:53PM (#21067138)
Since an async function is simply a function that returns a promise is there actually any difference between using async/await and using promises explicitly?
Re:V8 adds support for top-level await by dboreham on Tuesday September 24, 2019 @11:07PM (#21067219)
It takes longer to boil your brain.
Re:V8 adds support for top-level await by jinglebells on Wednesday September 25, 2019 @06:18AM (#21069332)
If you're compiling to ES2016 or lower, it will turn the promises into state machines.
Re:V8 adds support for top-level await by eurasiantiger on Wednesday September 25, 2019 @02:51AM (#21068371)
Terseness and readability towards less asynchronously minded folk
Re:V8 adds support for top-level await by BigJono on Tuesday September 24, 2019 @10:57PM (#21067170)
None, as far as I know
Re:V8 adds support for top-level await by gregors on Wednesday September 25, 2019 @10:05AM (#21070871)
"logical" race conditions can still occur. Eg. 3 lines of code should run without interrupt. The inclusion of an async operation within this block now causes context switch (execution switch). I've had to debug this tricky situation in external libs before.
Re:V8 adds support for top-level await by derangedHorse on Wednesday September 25, 2019 @08:50AM (#21070236)
I don’t understand how the async/await syntax changes anything. It’s really just syntactic sugar used to manipulate promises isn’t it?
Re:V8 adds support for top-level await by Gaelan on Tuesday September 24, 2019 @07:34PM (#21065873)
> two sequential lines of code are no longer two truly sequential instructions

How is this different from normal multithreading?

Re:V8 adds support for top-level await by eropple on Tuesday September 24, 2019 @07:41PM (#21065936)
Normal, which is to say preemptive, threading can pause your execution arbitrarily.

You can wedge a NodeJS interpreter by not yielding, but you also have control over when that yielding happens.

Re:V8 adds support for top-level await by _bxg1 on Tuesday September 24, 2019 @07:43PM (#21065953)
I suppose it's not, but it is different from normal JavaScript. I guess in multithreaded languages it's not such a big leap.
Re:V8 adds support for top-level await by desc on Tuesday September 24, 2019 @08:08PM (#21066149)
> 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 much the whole point of locking mechanisms, so under normal circumstances they aren't necessary for JS.

The same claim can be made for Visual Basic. This always sounds like a stronger guarantee than it actually is. In practice, the exact same mistakes get made irrespective of what the runtime provides.

Ultimately, people have to learn about race conditions in order to write correct code in a nontrivial system. Brushing the 'majority' of such cases under the carpet just makes it harder to educate them.