Proposal: `await [p1, p2]` (equivalent to `await Promise.all([p1, p2])`)

# Olivier Lalonde (8 years ago)

I have no idea if this has been discussed already but I thought it'd be nice to have the following syntax sugar for async/await.

The idea would be that any array that follows await would be wrapped into a Promise.all() call. For example, await [p1,p2] would be the equivalent of await Promise.all([p1,p2]).

It would make some more complex expressions easier to read:

  const downloads = await Promise.all(regs.map(reg => client.get(reg.url, {
    responseType: 'arraybuffer',
  })))

vs

  const downloads = await regs.map(reg => client.get(reg.url, {
    responseType: 'arraybuffer',
  }))

In many async/await code bases, it might remove the last use case for typing Promise directly.

# Raul-Sebastian Mihăilă (8 years ago)

Then Promise.resolve([p1, p2]) should be like Promise.all([p1, p2]) ?

# Olivier Lalonde (8 years ago)

I don't think so, what do you mean?

# kdex (8 years ago)

This change is not backwards-compatible. Note that the semantics of the following example would change:

(async () => {
   const result = await [new Promise(resolve => {
     setTimeout(resolve, 1000);
   })];
})();

Now, what should result contain?

await can already be used on non-Promises. In case of arrays, the completion value will just be the same array of Promises, not an array of their corresponding completion values.

# Raul-Sebastian Mihăilă (8 years ago)

On Wed, Oct 26, 2016 at 10:25 AM, Olivier Lalonde <olalonde at gmail.com>

wrote:

I don't think so, what do you mean?

Conceptually, await is similar to Promise.resolve and this similarity is more useful than saving a few keystrokes.

# Jordan Harband (8 years ago)

Your suggestion would preclude having a promise for an array (exactly what Promise.all returns).

If you want await syntax for Promise.all, you'd need different syntax for it - and then, what about Promise.race? What about other future combinators?

# Olivier Lalonde (8 years ago)

Oh, I didn't realize await could be used on non promises :( Never mind, I guess!

# Olivier Lalonde (8 years ago)

I didn't realize await could be used on non-Promises, never mind. I wonder why that is, seems strange. Maybe so that async functions could be more easily swapped out with sync ones in code? I do think Promise.all should deserve special treatment because it is so common, unlike Promise.race (who uses that seriously?) and future combinators. But I'm not sure it is worth introducing new syntax for.

# kdex (8 years ago)

It's especially beneficial for designing APIs where you don't care about if users pass you a Promise or the actual data to work with.

Imagine a scenario where you would like to remove a set of files:

async function remove(filesArray) {
	const files = await filesArray;
	/* … work with `files` here …*/
}

In the scenario above, you could pass an array of files, or a Promise that resolves to said array; the function accepts both.

# Olivier Lalonde (8 years ago)

Right it makes sense, should have thought about that! An awaitAll (or other syntax) could be nice but it seems the general opinion is against.

# kdex (8 years ago)

Personally, I wouldn't mind such an operator, as I feel that the use of Promise.all clearly outweighs all other Promise combinators, but this could be an opinionated view.

IIRC, that even was up for standards discussion at some point (being called await* instead of await). I'm not sure what ever happened to that.

# Damian Senn (8 years ago)

I don't like the await* [] syntax, it doesn't really tell me what it's doing. I could imagine something like await.all [] or await.race [] desugaring to await Promise.all([]) and await Promise.race([]), this could also be expanded to whatever new functionality might be added in the future (assuming await.something could work).

# Michał Wadas (8 years ago)

Actually using Promise.all with async/await is usually code smell - you probably should await on values.

# Andrea Giammarchi (8 years ago)

avoiding parallelism? can you please elaborate a bit more what's the code smell, exactly?

# Michał Wadas (8 years ago)

You avoid only few very limited cases of parallelism.

When you use Promise.all you are awaiting either on all promises to resolve or first rejection, but in case of rejecton, other promises don't get cancelled/reverted. That's pattern not present in synchronous code. Awaiting on values is more similar to synchronous code. Awaiting for all promises can be necessary, but in most use cases it's better to start processing already available values as fast as possible. Though I appreciate map/filter methods from Array.prototype.

And on topic - await* is probably syntax to go (though I would recommend asynchronous iterators proposal). And on the margin - it would be nice to have functional map/filter/each/reduce on native promises (Bluebird have these and they are awesome).

# Andrea Giammarchi (8 years ago)

in case of rejecton, other promises don't get cancelled/reverted

yet, since cancelable Promises is something already available in bluebird and it will eventually land on JS land too (it'd be about the time, Promise.all is indeed yet another use case for cancelability)

So yeah, Promise.all is for optimistic use cases, but I wouldn't call it a code smell: it's just a pattern.

Promise.all([
  waitHourOn12,
  waitMinuteOn12,
  waitSecondsOn12
]).then(dingDong12);
# Cyril Auburtin (8 years ago)

await* would be cool, even if it saves just 10 chars.

2016-10-26 13:14 GMT+02:00 Andrea Giammarchi <andrea.giammarchi at gmail.com>: