Live data from Hacker News

V8 adds support for top-level await

chromium.googlesource.com

261–270 of 310 posts

Re: V8 adds support for top-level await

#261
post #176

Earlier quoted context omitted.

And they call average C developer less experienced in async. The only correct ‘update balance’ operation is: INSERT INTO CashFlow (date, income, expense) VALUES (:date, :income, 0) Get balance: SELECT sum(income)-sum(expense) AS balance FROM CashFlow What modern js still has to reinvent is in-client synchronizing storage which naturally resolves who waits on what (if at all). This is partially simulated by reactjs no…

Operational transformations are not the "only correct" way to update an integer and it comes with a number of performance and memory/storage consumption implications. >What modern js still has to reinvent is in-client synchronizing storage which naturally resolves who waits on what (if at all) I don't understand what this means but it makes me curious. What would be an example of this in one of the languages that hav…

SQL.

>it comes with a number of performance and memory/storage consumption implications.

Instead of selecting sum(), CREATE TRIGGER then and update a singleton on insert. You can even create a view with N recent transactions and catch inserts into it to maintain that N, if you don’t want a full history.

Re: V8 adds support for top-level await

#262

Earlier quoted context omitted.

While this is 100% correct, if the main function has returned then the process was going to end anyway (assuming there isn't additional code after the call to main). If there's a main loop, then the catch needs to be inside that loop, not outside of main. The only difference it will make here is to suppress the default stack trace[1] and errorlevel returned to the shell. If you are writing in this kind of "scripting"…

> While this is 100% correct, if the main function has returned then the process was going to end anyway (assuming there isn't additional code after the call to main). That's not necessarily the case (or maybe poorly worded), e.g.: async function main() { // code setInterval(() => console.log('hey'), 1000) } main() In real life, it would probably be a HTTP server holding up the process. It's true that you likely want…

You raise an interesting point. If you are doing anything non-trivial, you should definitely be using a main loop and catching errors inside that loop. You really don't want to rely on the default behaviour of orphaned timers, because that can get interesting.

I did a quick test just to see how bad things might get if you were to rely on orphaned timers like this. The important thing to keep in mind is that each of those timers is effectively its own thread, which can throw errors and terminate itself. But if those are orphaned outside of a runloop that can handle those errors, they will not be caught by the catch outside of main (which only catches errors thrown in the "main thread"). Rather, they become top-level, uncaught exceptions, which also terminate the process.

Here's an example illustrating what happens:

    async function main() {
        setTimeout( () => console.log( 'Hello' ), 3000 );
        setTimeout( function() { throw new Error('error 1'); }, 1000 );
        setTimeout( function() { throw new Error('error 2'); }, 2000 );
        throw new Error('oops');
    }

    main().catch( x => console.error( x ) );
The result here is that `oops` is displayed (the caught error from the "main thread") and then `error 1` is displayed, but the process is then immediately terminated. Neither `error 2` nor `Hello` are displayed.

Note that I use the term "thread" loosely, in the "green thread" sense. Hopefully the meaning is clear.

Re: V8 adds support for top-level await

#263
post #197

Earlier quoted context omitted.

I think it can be argued both ways. I've seen a large TypeScript codebase with a pre-commit hook that enforces use of const on all non-reassigned variables. With that being done everywhere, it made for easy reading - whether a variable was being reassigned or not effectively became annotated in its declaration. On the other hand, there are some good reasons not to use use const everywhere we can. Paul Sweeney lists a…

I don't think I'd call any of those reasons good; the main thrust of them is "const doesn't do everything, so don't let it do anything". If that line of reasoning is appealing, then one might as well continue using var.

The main benefit of let/const over var is that it's block scoped. The benefit of const over let is pretty much nothing, much. It only prevents some limited form of re-binding. You can still easily re-bind const variables from inside a function:

    const x = 1;
    (function() {
        const x = 2;
        console.log(x);
    })()
or from an argument:

    const x = 1;
    (function(x) {
        console.log(x);
    })(2)
So it has limited value in any code that uses closures.

Re: V8 adds support for top-level await

#264
post #127

Earlier quoted context omitted.

That would seem to make sense, using readFileSync() instead. I assume it would really do much the same thing as the await example. Is there any difference? If they do the same thing, then what's the benefit of async/await? I guess it's that you can now write your own "fs.readFileSync()" or something like that in JavaScript when needed.

fs.readFileSync() blocks the event loop preventing any other code from being run or other events/requests from being processed. Await yields control back so that other requests can be processed while the file is being read.

Ah I see. Genius. So is there ever a use-case for NOT using the Async/Await -version of readFile()? Is fsReadSync() now just legacy which we don't need any more?

Re: V8 adds support for top-level await

#265
post #48

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…

"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

#266
post #163

Earlier quoted context omitted.

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. St…

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()))));

Thanks. I stand corrected.

Re: V8 adds support for top-level await

#267
post #163

Earlier quoted context omitted.

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. St…

Maybe there’s a misunderstanding with how async/await works...

Apparently so — thank you!

Re: V8 adds support for top-level await

#268

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…

Race conditions in a single threaded application? Please get this Java developer out of here.

Re: V8 adds support for top-level await

#269
post #70
post #65

Earlier quoted context omitted.

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

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.

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

#270
post #221

Earlier quoted context omitted.

There are at least ten Free Software Common Lisp implementations and three proprietary ones that are still supported. There are four APL implementations, two of which are Free Software. As for Ada, I've read there are six Ada 2012 compilers, with GNAT being the only Free Software option; there are more, however, if you look to older Ada standards. It's interesting how these ostensibly more complex languages have comp…

Software development nowadays is as much about using trendy / hip tools than anything else, sadly. Especially web development.

Is it though?

The tooling is pretty wild and crazy but I see a lot of tools that really do solve problems.

Post reply on HN