Hacker News new | ask | show | jobs
by zazibar 1518 days ago
Now maybe it’s just my familiarity with Promises, but I look at the third example and I can quickly see an opportunity.

This entire article is built around the author's ignorance and could easily be summarised as "I avoid async/await syntax because I'm more familiar with promises". The author doesn't even appear to understand that async/await is syntactic sugar for promises.

7 comments

I did not take me long to reach the same conclusion. The article can be summarized as "I am ignorant of the meaning of async/await, thus I don't use it". This is perhaps one incremental improvement from "I am ignorant of async/await, thus I use it poorly". But in the wrong direction.
I didn’t read the article like that at all.

How would you handle two asynchronous saves which can happen in parallel without using a Promise.all? Don’t think you can…and that’s pretty much the entire point of the article.

Async/await is useless unless you are willing to serialize your calls defeating the entire point of async code.

Just because you use async/await doesn't mean you can't use Promise.all.

In fact, my immediate intuition with the await examples was to parallelize with Promise.all.

    await Promise.all([/* build promises */]);
Yeah they had that in the post.
> How would you handle two asynchronous saves which can happen in parallel without using a Promise.all?

This question doesn't make sense. Async/await is just a nicer syntax for interacting with promises. So my answer to your "gotcha" question is just:

  await Promise.all([..., ...])
There's nothing impure going on here. The majority of the time, async/await can make it much easier to see a code's control flow by getting rid of most of the Promise related cruft and callbacks.

I would call Promise.all a benefit here, as it makes it stand out where I'm doing something in parallel.

  const x = somethingAsync();
  const y = somethingAsyncToo();

  return  { foo: await x, bar: await y }
There is no point in returning one before the other because you need both?
I think you’re trying to recreate the semantics of Promise.all without using Promise.all.

You’re effectively saying that Promises are a better async programming paradigm than async/await…which is also what the author is saying in the article.

I'm not saying anything about promises vs async/await. The original comment said that you can't have 2 async things happen in parallel without Promise.all, my code snippet proves that you can.
But in JavaScript, these two awaits will not happen in parallel, you really need to await Promise.all() for that.
You've really missed the point spectacularly of that example.

Both those promises start, and both are waited for after both have started..

That is the same as promise.all... There's just an explicit order for the wait, rather than as they resolve, but the result is the same.

Now, promise.any.... You'd have a point...

This is correct, I wasn't paying attention.
In Javascript, a Promise is started as soon as it is created. In other words, this is not the `await` that starts the Promise.

If the first await is the slowest, the second one will return immediately (like calling .then on an already resolved promise).

+1 Notably, this is different in Python where promises (futures) are executed lazily, i.e. when you await them.
Pretty sure there can be unexpected behavior if you wait too long before you do those awaits at the end.
No, why would there be?
Promises are also just syntactic sugar to make your code look more synchronous, you can do everything with plain callbacks. Which I find ironic with the article that he argues against that but still just stops at the next turtle, instead of following his own advice and actually learning how Javascript and it's runtime works.
Not really correct.

    const fooP = fetch(a)
    const bar = await fetch(b)
    const foo = await fooP
Wait, why don't do that? What's the point?
Yup - I prefer async/await but that was actually a good example on optimizing multiple promises I had not though of before.
I avoid Javascript outright because async/await/promise is confusing to me. I blame it on being a PHP Programmer and likes things to run serially.
I felt the same way coming from a threaded language.

Learning the event loop, then promises, then async/await is a must. Today, you probably should throw typescript on top.

A steep learning curve just to get back to a typed language that can do things concurrently.

You do get used to it, but it is a mess of stuff.

Threads are their own steep learning curve, I think it's just hard to do two things at once.
It's easy to do two things at once when you can ask two different entities to do them for you (threads).

What's hard is thinking about how to coordinate the work they are doing for you: when to consider them done, how to ask them if they did the work successfully, what to do if they need to use the same tool at some point during the work etc.

This is ridiculous. Handling real threads is much more complicated than handling async calls and the event loop of JavaScript.
Languages with threading require learning techniques to use them safely and many, including myself, have learned how.

Even if concurrency is easier to get right on node I'd say the node ecosystem has just layered on complexity in other ways to get to something just as difficult to use overall.

Promises and async/await sugar are only the tip of the iceberg.

/r/gatekeeping
It drove me crazy too, until I needed to use Puppeteer which requires you to write async/await (there are Puppeteer implementations in other languages, but they all seem to make compromises I didn't want). Generally speaking, async/await allows you to write code that looks and feels serial. Perhaps try using one of the async libraries for PHP to wrap your mind around the concept of async/await (like https://github.com/spatie/async)
Hyperscript can help with this. https://hyperscript.org/

Makes using a bit of JavaScript relatively simple, just not much in Stack Exchange yet which means reading docs..

The author even implies in a footnote that switch statements are unusable. I mean, we probably all had painful experience with the “gotcha”, and I appreciate efforts towards safer designs. But I mean, let’s not be ridiculous. It works fine.
Agreed, I stopped reading after this sentence.
What the author wants is something like this:

    async {
        save()
        save()
    } catch (Exception e) {
        console.log("Handle error")
    }
async does not deliver this at all.
what the author wants doesn't exists because the two saves will not actually run in parallel in any case. Not with `async save(); async save();` nor with `Promise.all` nor with any callback or any other means.

the author is conflating parallel with concurrent programming.

and in (the mono-thread world of) javascript the two calls will still occurs sequentially.

This is only partly true, but misses the point.

Consider that 'save()' might do multiple steps under the covers (network, database, localstorage, whatever). Allowing those steps to run interleaved, if necessary (with Promise.all), might be quite different from serializing the 'save()' calls completely in the caller.

So while it is true that neither is truly parallel in the "parallel vs concurrent" sense, it is not true that the "sequential"/"concurrent" execution of both styles has the same performance characteristics.

There is a growing trend where people just memorize how to do things instead of understanding what those things actually do.