Live data from Hacker News

A brief look at async-await

javascript.christmas

31–40 of 47 posts

Re: A brief look at async-await

#31

  check()
    .then(result => {
      if (result) {
         // set state to finished
      }
      check()
        .then(result => {
          if (result) {
              // set state to finished
          }
          check()
            .then(result => {
              if (result) {
                 // set state to finished
              }
              check()
                .then(result => {
                  if (result) {
                    // set state to finished
                  }
                  check()
                    .then(result => {
                      if (result) {
                         // set state to finished
                      }

                      // set state to not done
                    })
                    .catch(error =>  // set state to failed);
                })
                .catch(error =>  // set state to failed);
            })
            .catch(error =>  // set state to failed);
        })
        .catch(error =>  // set state to failed);
    })
    .catch(error =>  // set state to failed);

For the love of everything that’s sacred, please don’t do this. The strength of promises is that they can free us from that exact kind of callback hell, and they do that by being chainable.

  const resultOrNull = await Promise.resolve(null).
       then(result => result || check()).
       then(result => result || check()).
       then(result => result || check()).
       then(result => result || check()).
       then(result => result || check()).
       catch(error => null);
Calling .then/.catch inside of a .then/.catch is a huge red flag. Almost always, you want to return the promise and chain instead.

Re: A brief look at async-await

#32

Earlier quoted context omitted.

well IMO that is much more difficult to read for me. Promises are nice because they have a single purpose, to resolve or reject a promised value. So when I see them, I can pretty much instantly understand what it's doing. `Promise.all` tells me that it's waiting for all of them to resolve at once, `Promise.race` tells me that the result will be the first of them to resolve or reject. With callbacks, everything is "cu…

I agree with you now that "async/await" is available (as I said in my article that I originally linked to). And thank you for providing a second use case to the one I listed in the article - it paid for all the time I wasted on HN today with this thread. ;) The little bit of magic that makes your code sane is the "await" in front of "Promise.all()" and makes it more elegant than the callback version.

>The little bit of magic that makes your code sane is the "await" in front of "Promise.all()" and makes it more elegant than the callback version.

I'd actually say that it's the `Promise.all` that makes it sane, the await could be replaced by a `.then` and be functionally the same.

Actually it might be even easier to read to someone who doesn't live and breathe javascript as it will keep the program flowing top-to-bottom:

    Promise.all([a(), b(), c()]).then(([a, b, c]) => {
      // do stuff...
    })
As with most things javascript, there are 9 different ways of doing it, and 3 of them will shoot you in the face...

Re: A brief look at async-await

#33
post #31

check() .then(result => { if (result) { // set state to finished } check() .then(result => { if (result) { // set state to finished } check() .then(result => { if (result) { // set state to finished } check() .then(result => { if (result) { // set state to finished } check() .then(result => { if (result) { // set state to finished } // set state to not done }) .catch(error => // set state to failed); }) .catch(error…

Came here to comment on that example as well. I started panicking that someone might actually do that.

Re: A brief look at async-await

#34
post #31

check() .then(result => { if (result) { // set state to finished } check() .then(result => { if (result) { // set state to finished } check() .then(result => { if (result) { // set state to finished } check() .then(result => { if (result) { // set state to finished } check() .then(result => { if (result) { // set state to finished } // set state to not done }) .catch(error => // set state to failed); }) .catch(error…

You’re right of course.

But you having the “.” dot one line above made my spine tingle in all the wrong ways. Not that it matters.

Re: A brief look at async-await

#36
post #31

check() .then(result => { if (result) { // set state to finished } check() .then(result => { if (result) { // set state to finished } check() .then(result => { if (result) { // set state to finished } check() .then(result => { if (result) { // set state to finished } check() .then(result => { if (result) { // set state to finished } // set state to not done }) .catch(error => // set state to failed); }) .catch(error…

You’re right of course. But you having the “.” dot one line above made my spine tingle in all the wrong ways. Not that it matters.

The dot one line above is the better style. Change my mind.

Pasting

  check()
    .then()
in node REPL gives :

  > check()
  undefined
  > .then()
  Invalid REPL keyword

Pasting

  check().
    then()
Gives the expected result.

More generally, Javascript rules about whether a newline constitutes the end of a statement or not are pretty confusing (at least for me), so I prefer using a form that makes it explicit when a statement continues on the next line.

Re: A brief look at async-await

#37
post #5

I appreciate that the author is trying to illustrate something with an intentionally contrived example, but there is really no need for "await" in his "chain()" function: function chain () { (function loop (i) { if (i > 5) { // set state to failed return; } check().then((result) => { if (!result) { return loop(i + 1); } // set state to finished }).catch((error) => { // set state to failed }); }(0)); } This is one of…

I agree. Promises solve superficial aesthetic problems that only beginners trip on and unnecessarily add dangerous hidden state and corner cases. You can further simplify that chain() function by removing promises altogether: function chain () { (function loop (i) { if (i > 5) { // set state to failed return; } check((err,result) => { if(err){//set state to failed return;} if (!result) { return loop(i + 1); } // set…

CPS is a very bad idea in JS at present.

CPS in scheme works because proper tail call optimization exists, so your call stack doesn't explode. In current JS, the only way to make that work is performing a nextTick or setTimeout on every single function which trashes performance of simple things due to exiting your code back to the event loop all the time.

There's a special place in hell reserved for companies that deviate from standards because of petty disagreements. Proper tail calls have been a part of the JS spec for 5 versions now. They are implemented in Safari and in popular embedded engines like duktape. MS and Firefox refused to implement. They were in v8 behind a flag, but were removed.

v8 devs pitched a fit about stack traces disappearing (even though they disappear across the event loop anyway). The webkit team showed that Chicken scheme's shadow stack works just fine and it's been in production for a long time now (without any issues I'd add). Instead, they insisted that they wanted to revise the standard to require marking tail-recursive functions.

They also talked about decreased performance, but JSC team seems to have implemented it with a minimal performance impact, so it's definitely possible. More importantly, JS is a language to make development easy -- we have wasm in development for when speed becomes an issue and it's faster anyway (the label proposal would have also solved the issue by giving devs a choice).

They then dropped their own proposal, but still simply refused to re-add the feature as per the spec in a bid to force a spec change. I have some understanding of not turning a feature on until a newer proposal is considered, but when they dropped that proposal and still refused to implement, they lost all credibility in my estimation.

https://webkit.org/blog/6240/ecmascript-6-proper-tail-calls-...

https://www.more-magic.net/posts/internals-gc.html

I think this is indicative of a general "we know better than you" attitude on the part of the engine designers (especially the ones that sit on the spec committee). Another amazing example of this is the private variable proposal. NEVER has a JS proposal received such outspoken disapproval. Complaints range from the mostly insignificant "it's ugly" to the important "it goes against JS's core prototypical nature" to the very important "refactoring and maintaining this will be a nightmare due to dedicated syntax and JS being so dynamic", "it looks like a normal JS property that is hidden, but it in fact has almost nothing in common with normal properties even though the access syntax looks similar" or "this screws with inheritance, subclassing, destructuring syntax, etc".

Instead of listening, they locked down all dissenting discussions on the proposal's github and are going full steam ahead. EDIT: some discussions are unlocked (see below for a decent argument summary).

https://github.com/tc39/proposal-class-fields/issues/150

Decorators, pipe operators, tuples, immutable records, and slice notation are all well-understood ideas. Most don't require huge amounts of work to implement, but result in large quality-of-life improvements for developers. Most importantly, they aren't really controversial at all and most are easily transpilable so devs could start using them today (unlike private vars which either don't actually transpile correctly or create a mountain of unreadable garbage)

Why can't we work on these things that have such wide user impact instead of forcing through controversial changes that only benefit a very few people?

Re: A brief look at async-await

#38

Earlier quoted context omitted.

As far as I can tell, json() also needs to be treated as a promise, and fetch doesn't take a callback as an argument Wouldn't the correct non-await version look like this? fetch(url).then( response => { response.json().then( json => { // do stuff }); }); This is already much worse then the await version, without any error handling yet. And if I need to call another promise in order, I'd need yet another level of call…

you can chain them and avoid the nesting. Anything a .then handler returns becomes the value of the next one like this: fetch(url) .then((response) => response.json()) .then((json) => { // do stuff }) Promises will wait until resolved, normal values will call the next handler "right away" (there's some nuance here and some edge cases about what "right away" means, but for the most part you never need to think about t…

In your last example is `someOtherUserRelatedStuffPromise` on the last line supposed to be `someOtherStuffPromise` from the third line?

Either way, there's a very interested construct with promises I didn't realize was possible, but makes sense now that I see it. I never thought about awaiting an initiated promise at any point later on.

Re: A brief look at async-await

#39

Presumably the "// set state to finished" involves a return statement, otherwise "check()" will continue to be called and ultimately the state will be set back to not done. This applies to both the async version and the chain() version. Personally I find it confusing that the comment hides a control flow statement when the text of the comment suggests that it's just setting a state variable. Surely a better compariso…

I think most JS programmers do something along the lines of...

    function check() {
        return new Promise(async (resolve, reject) => {
            for(let i = 0; i 
or...

    async function check() {
        for(let i = 0; i 
Though, the same thing could certainly be accomplished with pure promise chains. One could also use the setTimeout method in situations where elapsed time is more important than a fixed number of calls.

Re: A brief look at async-await

#40
post #27

Earlier quoted context omitted.

Apparently it's supposed to be some kind of advent calendar type thing, 25 posts in 25 days. Which explains the christmas tld.

Exactly that. Bekk, a Norwegian agency, has built a few advent calendars themed around various aspects of programming and product development. There’s FP, JS, Kotlin, UX, etc

[deleted]
Post reply on HN