top | item 41238676

(no title)

mrozbarry | 1 year ago

My biggest gripe with async await is when it's used by people that don't understand promises. They interpret await as "let promise run" and not "this blocks the flow." I had someone show me code where they wanted to preload a bunch of images, and effectively had a for loop and did an await on each image in it, effectively running it as slow as possible. I showed him `await Promise.all(imageLoadingPromises)`, and he was confused why we needed `Promise.all` here.

I also don't like how async/await ends up taking over a whole codebase. Often making one function async will cause you to update other functions to be async so you can do proper awaiting. We literally exchanged callback hell to async hell, and said it was better, but I'm not strictly convinced of this.

discuss

order

spankalee|1 year ago

It's not async/await that takes over a codebase, it's the async nature of functions period, no matter if you're using async/await, Promises, or callbacks.

Callbacks still have the function coloring problem: If you write a function which calls another function with an on-complete callback argument, then your function (usually) has to also take an on-complete callback in order to represent completion.

async/await makes this nicer, but it doesn't eliminate the underlying need to thread async completion all the way up your call stack.

throwitaway1123|1 year ago

> I also don't like how async/await ends up taking over a whole codebase. Often making one function async will cause you to update other functions to be async so you can do proper awaiting.

This is basically the function coloring problem. There was some ardent discussion about this a few weeks ago on HN [1], where the top comment positioned function coloring as a feature, because it highlights where expensive operations like IO might potentially be happening in your application.

I saw a comment recently where someone pointed out an old API in Java where comparing two URLs for equality initiates a DNS request, and so something as simple as putting a URL in a hash table could end up involving a network request [2]. So maybe it's reasonable to color functions that connect to the network at the very least. If I used a URL comparison library and it returned a promise it would immediately set off alarms in my mind.

[1] https://news.ycombinator.com/item?id=41001951

[2] https://news.ycombinator.com/item?id=41143458

phyrex|1 year ago

That could be much better solved through coeffects, but unfortunately most languages don’t support that. Doesn’t mean using async functions is a good way for this either

lofenfew|1 year ago

>We literally exchanged callback hell to async hell, and said it was better, but I'm not strictly convinced of this.

It's obviously better. It's a bit unfortunate how much the history of the design decision shines through in the current solution, but it's unequivocally an improvement.

I would prefer an approach where calls to "async" functions are implicitly awaited unless a keyword turns then into a promise, and all functions are implictly treated as async as needed, unless a keyword specifies that they return a promise, which should be awaited instead. This would make the majority case clearer, and force you to make the minority case explicit where it's currently implicit.

I don't think this would help your coworkers who don't understand promises very much though.

tyleo|1 year ago

Chapter 15 of the 2007 release of "Programming Languages: Application and Interpretation" gives a really good motivation for the async/await syntax. Here is a link: https://cs.brown.edu/~sk/Publications/Books/ProgLangs/2007-0...

> I would prefer an approach where calls to "async" functions are implicitly awaited unless a keyword turns then into a promise, and all functions are implictly treated as async as needed, unless a keyword specifies that they return a promise, which should be awaited instead. This would make the majority case clearer, and force you to make the minority case explicit where it's currently implicit.

This is a very interesting idea and feels good in an initial 'gut check' sense.

mrozbarry|1 year ago

I prefer the raw promise syntax. It makes the promise chain look more like what it is, an asynchronous pipeline, and you don't need to litter async everywhere.

    const myAsyncThing = async (init) => {
      let value = await task1(init);
      value = await task2(value);
      return value;
    }

    const myPromiseThing = (init) => task1(init).then(task2)
I know this is a relatively simple and contrived example, but there are some times where async/await very much is bulky and gets in the way of just writing code.

alemanek|1 year ago

I love async but very rarely use await. It makes inversion of control patterns super easy and avoids deep logic and instead get something much more readable.

I treat await as a code smell and always triggers me to evaluate if we really need to be waiting for the result in this place. Most of the time they shoukd just return the promise or put something in a then.

People are going to misuse stuff but it doesn’t mean we shouldn’t use appropriate tools when appropriate.

EDIT: this is especially true for NodeJS where lots of frameworks are promise/async aware and support you returning a promise to them.

WatchDog|1 year ago

There is zero reason to use async without await, unless I’m missing something.

The number of await calls in your codebase should always be greater than the number of async modifiers.

craftkiller|1 year ago

> They interpret await as "let promise run"

This is actually how rust handles async/await. If nothing is polling the future then the future is not running. If you want background execution like javascript then you need to hand it off to an executor (for example via `tokio::spawn`). Its actually pretty nice because then you can build a future and pass it around but you can decide if/when you want to execute it later.

That being said, you still wouldn't want to do a for loop awaiting each future.

kccqzy|1 year ago

I agree. People should gradually build up their intuition from lower abstractions to higher. People should be banned from using async/await unless they had first experienced callback-based code, and then promise-based code. Going straight to async code is like asking people to run before they have learned to walk.

rileymat2|1 year ago

It is not clear to me where you stop the tunneling down the abstractions. It seems arbitrary to each person to their knowledge base.

I have a degree in Electrical Engineering, and don't understand how programmers can function not understanding physical computer architecture.

But clearly, that's not the bar which most come from.

THBC|1 year ago

What? In JS async/await is _literally_ syntactic sugar for returning/thening promises.

moralestapia|1 year ago

Can you give a concrete example of "async hell"?