Live data from Hacker News

V8 adds support for top-level await

chromium.googlesource.com

221–230 of 310 posts

Re: V8 adds support for top-level await

#221

Earlier quoted context omitted.

There are at least three other C/C++ implementations - AMD and Intel each have one, and MSVC. That's a total of six compilers for the language.

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.

Re: V8 adds support for top-level await

#222

Earlier quoted context omitted.

Because all the promises are waiting on `fileSize`, right? But do you mean that JS 1. will read `totalSize` then 2. do the asynchronous call, then 3. add and set? Seems like it's ambiguous and JS could just as easily read `totalSize` after the call, and all would be OK. Or is the ordering specified? Thanks for this clever example!

The ordering is specified left to right. totalSize += await getSize() becomes totalSize = totalSize + await getSize() So all the map callbacks run one by one, read totalSize as 0, and then suspend waiting for getSize(). Each one then resolves and assigns totalSize to be 0 + the size. The race is what order the getSize() calls return in since only the last one will control the return value. Otherwise the issue isn't a…

What if you change it to

  totalSize = await file.getSize() + totalSize; 
Would it be fine then?

Re: V8 adds support for top-level await

#224
post #47

Earlier quoted context omitted.

Wow, I had completely forgotten the existence of void in JavaScript. Why is it needed here? To force an expression without using the parentheses? Edit: Yes, it seems so, and this usage with functions is explicitly documented there: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

Yep. Exactly why. Seems silly since it doesn’t really care for types in the first place.

[deleted]

Re: V8 adds support for top-level await

#226

[removed]

Nothing would change here.

Normally, await can only appear in a method that has been marked as async. However, when you write toplevel code (code that's not wrapped in a function), you can't mark the function as async (because there is no function) so you can't use await.

Enabling toplevel await fixes that.

Re: V8 adds support for top-level await

#227

[removed]

Nothing. It's just that you can have const result = await someFetchOrSomething(str); return result.foo; while not inside an async function. You still can't use it in a non-async function.

You can't return when you're not in a function ;-)

Re: V8 adds support for top-level await

#228
post #66

Earlier quoted context omitted.

No magic is rich — they swallow errors, for one. In any case, I don't think anything I said precludes the creation of promises outside of async functions, in fact quite the opposite. The difference is that the runtime would implicitly await the resolution of a promise returned from a function (any function, there'd be no such thing as an "async function") and if you actually wanted things to progress asyncronously yo…

How is swallowing errors magic? try/catch does that and predates ES3. To clarify your example, what about: function foo() { const val = async (1 + 2) return val; } const x = foo(); Does the `x = foo()` block/implicitly await? > if you forget an await you've probably introduced a bug, and the only way to know is ... docs Given that async is "contagious", I'm having a lot of trouble imagining a scenario where a codepat…

But try/catch makes swallowing errors explicit, you have to catch it to swallow it. With promises it's the opposite situation, errors will be swallowed unless you explicitly handle the rejection. At least the runtimes have grown up to show console output when there's an unhandled rejection, but man it was pretty dark for a while.

> Does the `x = foo()` block/implicitly await?

Yes, that's what I'd expect, because `foo` returns a promise.

> Unless you're just saying that the bug would be apparent as soon as you ran the code, but the syntax checker wouldn't flag it for you?

It may or may not be apparent even from running the code, consider the following:

    let data
    try {
        data = readFile('some-file.csv', 'utf8')
          .split('\n')
          .filter(l => !!l)
          .map(l => l.split(','))
    } catch (e) {
        data = []
    }
It's not particularly good code, granted, but it's also not a contrived example. What's the bug? Well, assuming `readFile` is sync, and `some-file.csv` is a nice csv file with no surprises in it, this should make data an array filled with data from said file. If the file is empty, it's just going to yield an empty array. If the file can't be read for some reason and `readFile` throws an error, it'll be an empty array.

Now make `readFile` return a promise instead and `data` will always be an empty array, regardless of whether the file exists, can be read, or otherwise all conditions for a happy path are met. Why? No `split` method on the promise.

The problem isn't promises of course, it's the fact that we're doing too much in a try clause, or at least not dealing with specific errors properly. But let's be honest – who hasn't seen (or even written?) code like this in the past?

It might've even worked fantastically well for a long time, years even, until someone comes around and changes `readFile` to be async, for reasons, and now it breaks in a subtle way and it's fun and games trying to find why `data` is always an empty array even though it seems everything should be fine. Actually, it doesn't even have to be `readFile` that changes, it might be a function that it depends on, causing bugs further up the call stack. It happens, no matter how semantic our versioning is.

If however the runtime would always implicitly await return values, and you'd have to explicitly mark statements as async to break out of that, then this code would continue to function regardless of whether `readFile` or one of its dependencies returns a promise or the actual file contents, because the runtime would deal with it. As it is now, you have to go and change all code that calls `readFile` to be async, so you can await, meaning anything further up the stack also needs to be async, so you can await. It's a bit of a foot gun I think.

In any case, it's just a thought and at best a half baked one at that. I just find the async/await semantics to be backwards, and while I've used it for a few years at this point I still keep running into dumb situations like the above. Maybe I'm just a bad programmer, I'm certainly not excluding that as a possibility. :o)

(Apologies for the wall of text.)

Re: V8 adds support for top-level await

#229

Earlier quoted context omitted.

> also ignorant, because 1990s C was decidedly synchronous There was definitely threading in C in the 1990's, and threads are asynchronous by nature. There's a whole class of synchronization bugs that C and C++ developers had to learn to deal with, and while JavaScript developers get to avoid some by the nature of there being a single thread, that doesn't necessarily exempt them from all of them.

Threading implementation was async, not the programming model. Async programming style/model(as far as I'm aware) refers to the use of callbacks or coroutines, neither of which was common at all in C in the 1990s. Indeed, nginx caused big waves due to its superior IO performance as the first popular async http server released in 2004. But correct me if you have a different understanding of the term.

Your post manages to say nothing correct. Javascript did not invent callbacks, asynchronous programming, or event driven programming. Nodejs popularized it in the 2010s but you are claiming credit for something that has been in common use since the 70s. I have no clue how anyone can speak with such authority while clearly having not done a cursory glance at programming APIs available in the 80s and 90s.

Lighttpd was released before nginx and was wildly popular for a good while. Not to mention other servers like AOLserver in the 90s.

The use of non blocking sockets was nothing new, used heavily in C code throughout the 90s and is the basis of asynchronous processing (refer to Stevens Unix network programming). You should also read documents by John Ousterhout written in the 90s about this topic.

Now just about every major GUI library was targeted in C or Pascal and used an event driven callback model. You can refer to the Windows API, the modern Mac carbon API which was developed in the 80s at Next and the older Mac SDK. The Windows SDK allows event driven programming for UI and IO. tcl/tk. Just about anything on top of X (ie Motif, GTK). The list will go on and on.

Do some research before making bold claims about C programmers not understanding asynchronous programming and callbacks.

Also I think the other reply is correct in asserting that your definition of async is making distinctions without differences.

Eg from 1995: https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf Note that event driven programming was nothing new in 1995.. it was the basis for the Windows api designed years prior after all, but this was around the time that multithreading was pushed for everything.

Heck fibers: https://docs.microsoft.com/en-us/windows/win32/procthread/fi... have existed in the Windows api since at least 95.

Re: V8 adds support for top-level await

#230
post #137

Earlier quoted context omitted.

If all you're doing on catch is forwarding to `console.error`, you could just write: // code Outputting errors to console is the default behavior.

There's an important difference: the process will crash if you don't catch the error.

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" style, you probably don't want to suppress errorlevels, so leaving out the catch is not only simpler, it is safer.

[1] You may get a stack trace with an Error object, but not the default one from the Node process.

Post reply on HN