Live data from Hacker News

JavaScript async/await implemented in V8

chromium.googlesource.com

191–200 of 227 posts

Re: JavaScript async/await implemented in V8

#191
Man, I used to love the times when try/catch was used to exception only, and with exceptions that leaves the program in a bad state, I used to think when you see a throw something really bad is going on, not just a simple ajax fail.

Dont know why people love so much async/await. In the end of the day, this all (in node land, for instance) will be just a function call in the libuv, this will never change, this is because the pattern is really good.. Why overcomplicate that?

Re: JavaScript async/await implemented in V8

#192
post #175
post #127

Earlier quoted context omitted.

Can anyone point to a good explanation why this is preferable to cooperative threads (coroutines)? I.e. the above code could easily be written as function main() { try { const res = fetch('https://api.github.com/orgs/facebook'); // yield here const json = res.json(); // yield here console.log(json); } catch (e) { // handle error } } and the runtime would automatically yield this coroutine and let other coroutines run…

The explicitness is the reason currently you can assume* that if nobody will ever modify variables unless you explicitly give up control somehow, if you were to have implicit await then that would no longer be the case and any function call could theoretically pause the function and give up control to other functions. *certain DOM APIs due violate this contract, notably window.open() on firefox pauses everything but…

Just to expand a bit upon this: That you can assume a single thread simplifies the code immensely, e.g. when modifying state. It's important to be explicit about when this assumption is broken.

Re: JavaScript async/await implemented in V8

#193
post #124
post #23

Earlier quoted context omitted.

The great thing about let and const, for me, is that it gives you crucial information about variables without having to look further down. const should be the default, and if you're going to reassign it, then use let. In most code, you'll use const on the vast majority of variables, and it'll make let assignments stick out, which helps a lot when you're browsing the code or refactoring.

This right here. One of my friends (a more experienced developer) told me at coffee one day, "I use const for everything" which really stuck with me. It really helps make it clear if you need a mutation to have let stand out.

I just wish let was in fact const (and something like "local" could be let), simply because the keyword let is nicer to type, easier to read, and more importantly better in line with the meaning of let in Lisp/Scheme/ML/OCaml/et al.

Re: JavaScript async/await implemented in V8

#194

I'm definitely rooting for the feature to be included in the spec as soon as possible, but I'm a little weary when features are added to the engine before being standardized. Object.observe, anyone?

Things should be clearer now that the "Stage Process" [1] is more transparent. Object.observe made it only as far as Stage 2 ("Draft"), but async/await has already pushed on to Stage 3 ("Candidate"), making it much more likely it will hit Stage 4 ("Final") just as soon as a plurality of web browsers support it. (...and as soon as it hits Stage 4 it will be included in that years final spec, under the new annual review process.)

[1] https://tc39.github.io/process-document/

Re: JavaScript async/await implemented in V8

#195
post #46

Earlier quoted context omitted.

I hope the node APIs are changed/extended to return promises eventually so I don't have to keep on using promise wrappers for all of them.

Is there a reason you always wrap them? Even if it's awkward I tend to leave most platform APIs alone and treat them as special cases if I'm doing something, say, promises or messages.

Promises are much each to compose. Promise objects can be passed around and reused. (Multiple things can wait on the result of the same promise.) Code is much easier to read with flat .then() and .catch() chains, versus sometimes the "pyramid of doom" callbacks can create. Code is much, much easier to read with Promises when you can use async/await, and getting everything wrapped to promises now makes it that much sooner you can use async/await.

Re: JavaScript async/await implemented in V8

#196
post #116
post #112

I can't see how wrapping everything in a promise and a try/catch, plus adding async/await is any easier then a callback.

Exactly! When you count for nested try/catchs you see no significant improvement

Why would you nest try/catches? At worst you get try/catch parades:

    try {
      await thing1()
    } catch (e) {
      console.log(e)
    }
    try {
      await thing2()
    } catch (e) {
      console.log(e)
    }
    // ... and so forth ...
That's still nothing like the pyramids you get in callback world.

Re: JavaScript async/await implemented in V8

#197

Earlier quoted context omitted.

It's okay but clumsy. It's a state machine, not a busy loop, but the compiled code is a lot more verbose than the input code (and so you pay a latency penalty on the client). The developer experience is also sub-par: you'll get regenerator stack frames in any of your stack traces, and it interacts poorly with babel-watch. You can do it, it's not insane, but native async/await will be much, much nicer.

Can you elaborate on "it interacts poorly with babel-watch."?

IIRC under babel-watch it required me to include babel-polyfill at the top of my main script, but under babel-node it prevented me from including babel-polyfill at the top of my main script. (babel-polyfill has a check so that it can only be required once, and errors out otherwise.) That meant I needed to keep commenting/uncommenting that line when I wanted to debug things.

There were also cases where I wasn't sure if babel-watch was reloading dependencies properly if I used async code in a file, which is why I had to keep switching to babel-node or running the code through babel and inspecting the generated code to debug. Overall, it just felt very new and unpolished (which I guess it was...I was working with it around March, so babel-watch was < 1 month old and babel async/await was about 2-3 months at the time) to be relying on all the time.

Re: JavaScript async/await implemented in V8

#198
post #116

Earlier quoted context omitted.

Exactly! When you count for nested try/catchs you see no significant improvement

Why would you nest try/catches? At worst you get try/catch parades: try { await thing1() } catch (e) { console.log(e) } try { await thing2() } catch (e) { console.log(e) } // ... and so forth ... That's still nothing like the pyramids you get in callback world.

"Pyramids" are not that useful for complex flows, just as synchronous-looking code, but for something as simple as your example they are equivalent in complexity, maybe even less complex, because they don't have additional implicit behavior introduced by async/await. Still, worlds better, than CSP with channels.

Re: JavaScript async/await implemented in V8

#199

Earlier quoted context omitted.

I don't understand. I also like JS async/await and like JS and node in general but .NET is simply beautiful IMHO (given you are using F# or C#). Why would you rather not write .NET code?

c# is a great language but many people don't want to have to specify type information so often or create classes so often. Even many statically-typed languages don't require as much List stuff. Also, everything outside of the language itself sucks. The frameworks, the operating system is has to run on, the community, etc.

c# has var as long as the variable is being assigned. var t; is a readability nightmare to me anyway.

As for creating classes so often, they are adding better support for tuples in the next version (c# 7).

Re: JavaScript async/await implemented in V8

#200

Earlier quoted context omitted.

Why would you nest try/catches? At worst you get try/catch parades: try { await thing1() } catch (e) { console.log(e) } try { await thing2() } catch (e) { console.log(e) } // ... and so forth ... That's still nothing like the pyramids you get in callback world.

"Pyramids" are not that useful for complex flows, just as synchronous-looking code, but for something as simple as your example they are equivalent in complexity, maybe even less complex, because they don't have additional implicit behavior introduced by async/await. Still, worlds better, than CSP with channels.

async/await ends up being the less complex thing, my "simple" example is an extreme that sometimes but rarely happens. When was the last time you saw that in synchronous code? It happens, certainly but the synchronous default is to only handle what you can handle and then pass everything else back up the chain. The asynchronous default with async/await is the same, and you can rely on default error propagation in the natural default case:

    async function doTheThing() {
      await thing1()
      await thing2()
    }
That just works, if there's an error in thing1(), doTheThing() stops at that line and returns the rejected promise to whatever called it. The callback world is clearly the more complex here, where all error handling has to be properly wired and there is no default handling. The node callback equivalent to the above is:

    function doTheThing(callback) {
      thing1(function (error, value) {
        if (error) callback(error, null)
        thing2(function (error2, value2) {
          if (error2) callback(error2, null)
          callback(null, true)
        })
      })
    }
You can't forget either if (error) check or else errors will just silently be eaten/ignored.

The "implicit behavior" introduced by async/await are essentially the same things you are used to in code without async/away, such as the way try { } catch { } and throw naturally work in synchronous. That alone should be considered a simplifying improvement.

Post reply on HN