How about awaiting Arrays ?

# Andrea Giammarchi (7 years ago)

Not the first time I accidentally type the following:

const allTheThings = await [pa, pb, pc];

I am assuming that JS will implicitly realize that'd be a Promise.all([pa, pb, pc]) call but nope.

Then I also realize it'd be cool to have other shortcuts too that play nice with arrays such:

Array.prototype.all = function all() { return Promise.all(this); };
Array.prototype.race = function race() { return Promise.race(this); };

// with the lovely addiction of ...
Array.prototype.any = function any() { return Promise.any(this); };

// with Promise.any being (sorry it was a tweet)
Promise.any = $ => new Promise((D,E,A,L) => {
  z = [];
  _ = $.map(($, i) => Promise.resolve($)
        .then(D, O => { z[i] = O; --_ || E(z) })
  ).length
});

So that ...

const allTheThings = await [pa, pb, pc].all();

Yay? Nay? Silly? no-way?

I thought it was worth it to point this out.

Best

# T.J. Crowder (7 years ago)

On Fri, Mar 3, 2017 at 12:43 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:

Not the first time I accidentally type the following:

const allTheThings = await [pa, pb, pc];

I am assuming that JS will implicitly realize that'd be a Promise.all([pa, pb, pc]) call but nope.

The problem is that an array of promises is a perfectly valid promise resolution value. (And that the proposal is now at Stage 4. :-) ) To do this, await would have to treat arrays specially in a way that promises don't. That seems like something await shouldn't do. You might propose awaitall, awaitany, awaitrace or similar...

Then I also realize it'd be cool to have other shortcuts too that play nice with arrays such:

Array.prototype.all = function all() { return Promise.all(this); };
Array.prototype.race = function race() { return Promise.race(this); };

Side note: I'm fairly sure all isn't websafe as an Array.prototype function (isn't that why ES5 used every?).

I don't think arrays need special promise-related functionality in the standard lib. But if they got it, I'd want it to be reflected in the naming, e.g. [].promiseAll, [].promiseAny, ... Both for clarity and for web safety (I'm fairly sure all on Array.prototype wouldn't be web-safe).

-- T.J.

# Andrea Giammarchi (7 years ago)

If this is what we gonna have

[].promiseAll

then I'd rather

Promise.all()

You made some fair point, I guess there's nothing to see here.

# Matthew Robb (7 years ago)

I think this conversation needs to happen but I am not sure baking it into Array facilities makes the most sense.

In my experience with async/await I am very often needing Promise.all but in some cases the other forms of multi promise capabilities. What if we expanded the keyword await.all [...]; await.race [...] or add a new context for of outside for loops but this would be limited to P.all behavior await of [...]?

  • Matthew Robb
# T.J. Crowder (7 years ago)

On Fri, Mar 3, 2017 at 3:28 PM, Matthew Robb <matthewwrobb at gmail.com> wrote:

I think this conversation needs to happen but I am not sure baking it into Array facilities makes the most sense.

In my experience with async/await I am very often needing Promise.all but in some cases the other forms of multi promise capabilities. What if we expanded the keyword await.all [...]; await.race [...]

Heh, I was thinking of that too, as an alternative to the awaitall and such I suggested to Andrea so we didn't need to add Yet More Keywords. :-)

await.all iterable;

instead of

await Promise.all(iterable);

? That seems pretty clear to me, and doesn't seem like a big specification or implementation burden (he said, talking through his hat).

-- T.J.

# Michał Wadas (7 years ago)

Actually I would go with

await ...expr;

As sugar for:

await Promise.all(Array.from(expr))

On 3 Mar 2017 17:15, "T.J. Crowder" <tj.crowder at farsightsoftware.com> wrote:

On Fri, Mar 3, 2017 at 3:28 PM, Matthew Robb <matthewwrobb at gmail.com> wrote:

I think this conversation needs to happen but I am not sure baking it into Array facilities makes the most sense.

In my experience with async/await I am very often needing Promise.all but in some cases the other forms of multi promise capabilities. What if we expanded the keyword await.all [...]; await.race [...]

Heh, I was thinking of that too, as an alternative to the awaitall and such I suggested to Andrea so we didn't need to add Yet More Keywords. :-)

await.all iterable;

instead of

await Promise.all(iterable);

? That seems pretty clear to me, and doesn't seem like a big specification or implementation burden (he said, talking through his hat).

-- T.J.

# T.J. Crowder (7 years ago)

On Fri, Mar 3, 2017 at 4:51 PM, Michał Wadas <michalwadas at gmail.com> wrote:

Actually I would go with

await ...expr;

As sugar for:

await Promise.all(Array.from(expr))

Which is great for Promise.all, but leaves us without race or things that may be added in future (like Andrea's any). (Granted all has to be the dominant use case...)

Why the Array.from part of that?

-- T.J.

# Andy Earnshaw (7 years ago)

On Fri, 3 Mar 2017 at 16:51 Michał Wadas <michalwadas at gmail.com> wrote:

Actually I would go with

await ...expr;

I think await.all is clearer and more explicit, and await.race could be added too.

Also: here's previous discussion that didn't go anywhere: esdiscuss.org/topic/proposal-await-p1-p2-equivalent-to-await-promise-all-p1-p2 .

# Michał Wadas (7 years ago)

My mistake Array.from is not necessary because Promise.all accepts any iterable.

Though I don't believe .race to be common use case (especially when we consider it's edge case with empty array).

Hsving parity with spread and rest parameters seems consistent for me.

# Mark S. Miller (7 years ago)

On Fri, Mar 3, 2017 at 8:51 AM, Michał Wadas <michalwadas at gmail.com> wrote:

Actually I would go with

await ...expr;

I have not liked any of the prior suggestions on this thread. But this one is interesting. It has no compatibility problems, it composes nicely, and it suggests its meaning clearly.

# Mark S. Miller (7 years ago)

On Fri, Mar 3, 2017 at 12:27 PM, Mark S. Miller <erights at google.com> wrote:

On Fri, Mar 3, 2017 at 8:51 AM, Michał Wadas <michalwadas at gmail.com> wrote:

Actually I would go with

await ...expr;

I have not liked any of the prior suggestions on this thread. But this one is interesting. It has no compatibility problems, it composes nicely, and it suggests its meaning clearly.

I should have read ahead. await.all and await.race also have these virtues, and there's no generalization of await ...expr that naturally expresses race.

# Isiah Meadows (7 years ago)

First, I'll start out with this: I tend to be very adverse to new syntax, but I'll draw exceptions for things that enable whole new ways of looking at and manipulating code, like async functions and decorators, or things that enable new functionality altogether, like function.sent or private class fields. Things that haven't hit that bar for me include the bind syntax proposal (beyond function pipelining) and the await.all/await.race idea here.

BTW, I had some ideas on unifying that with observables at the syntax level here, particularly with my parallel and await parallel ideas there: tc39/proposal-observable#141

Basically, it unifies the common case of merging promises and observables with a fairly low syntactic footprint.

As for Promise.race, I see it much less frequently, and it's much simpler and faster under the hood to implement due to less state needed, so I didn't see the need to add support for that.


Isiah Meadows me at isiahmeadows.com

# Matthew Robb (7 years ago)

Honestly Isiah my largest motivation for thinking this is worth solving boils down to the fact that async/await does a good job of hiding the promise and generator based implementation under it but this falls down so fast when adding Promise.all.

I'm helping a new person learn JavaScript right now and he's using fetch to get some JSON. Explaining the first then returning res.json() and the second one chaining as well as 'this' considerations was a disaster. He conceptually understands asynchronous code so when I backed up and did the same thing with async/await he just got it. Saving him from needing to learn anything about promises until later on.

In my opinion if a layer of sugar doesn't fully abstract the layers it sits upon then it's an incomplete and confusing feature. I'd go so far as to say that async/await should always support every capability of promise without anyone touching Promise directly.

# Andrea Giammarchi (7 years ago)

glad this topic moved some interest, but I'd like to share my opinion about locking down to Promise.all only any possible solution, as example:

I don't believe .race to be common use case (especially when we consider

it's edge case with empty array).

As mentioned already, fetch API is a clear case where you want to fetch races, if not actually fetching any in case the resource wasn't present in the local cache.

Fetch API has this funny little gotcha that erase somehow unpredictably and Promise.any would solve many things there, granting that at least, instead of an error, the user donwloaded the last online version of that resource and tried to store it again.

Race on NodeJS side plays also very well when you have an pool of n odes pointing at different DB instances, all synchronized and happy, all capable of falling back to other nodes.

Race in these cases is a way more common use case.

Promise.all is actually useful for list of tasks to wait for, like loading modules asynchronously, but for all cases where the full list ain't needed, it makes the program slow for no reason.

I know you all know these things but then again, I use race and any quite often and reading "not a common use case" didn't match reality here.

Last, but not least, await.all and friends looks even better proposal than [].all to me, specially because it's not related to Arrays and it can work with any iterable.

It's also future friendly for .race and .any too :party-emoji:

Best

# Isiah Meadows (7 years ago)

I'm going to toy with my strawman some, previously introduced here: tc39/proposal-observable#141

In particular, I'm going to try to address some of these concerns in an updated proposal. My goal is to come up with something that unifies both Promises and Observables, and can model all these forms of data flow declaratively (except second) and elegantly:

  • Await all success, await first failure: Promise.all
  • Await all success, await all failure: N/A (not sure of use case)
  • Await first success, await first failure: Promise.race
  • Await first success, await all failure: Promise.any

I know it'll be difficult, but I'd like to come up with something that will be fast, usable, and highly intuitive.

Isiah Meadows me at isiahmeadows.com

# Gil Tayar (7 years ago)

As someone who teaches JavaScript a lot, I believe that not explaining what promises are when teaching async/await is not possible, because await only works on promises. You need to at least understand that promises are "async values" to understand and use aysnc/await. What is abstracted away is the use of chainable promises and .then/.catch, and not the promises themselves.

So saying that Promise.all accepts an array of promises and returns a promise that is resolved only when they all resolve is not leaking the async/await abstraction. It's still "OK".

There are hundreds of little syntax sugars we can add to the language. We should choose carefully because each one makes the language more complicated. Abstracting away promise chaining with async/await is a game changer, and is worth the "syntactic sugar" - even more so IMHO than class abstracted away prototype (which is a much leakier "syntax sugar"). Abstracting away Promise.all with syntactic sugar gives us little gain, and in my opinion is not worth it.

# Axel Rauschmayer (7 years ago)

I like the following way of using Promise.all():

const all = Promise.all.bind(Promise);

const allTheThings = await all([pa, pb, pc]);
# Andrea Giammarchi (7 years ago)

Nice one, but at that point const all = a => Promise.all(a) seems a

better option.

I think the point here is that we all need that and repeating the pattern every single time feels like a very clunky experience.

await.all looks like a win 🎉