await spread operator (await...)

Similar fashion of spread operator ..., but await each promises before expanding with the new operator await...

Proposal link

// const [foo, bar] = await Promise.all([taskFoo(), taskBar()]);
const [foo, bar] = [await...[taskFoo(), taskBar()]];

const obj = {await...{name: getAsyncName()}, await...{surname: getAsyncSurname()}};

otherFunc(await...[getAsyncName(), getAsyncSurname()])

This seems like it overlaps with
https://github.com/tc39/proposal-await.ops, and doesn’t provide for race/allSettled/any semantics.

This one, however, does provide a brand new combinatorial - on objects with Promise-valued properties - which seems like something that should have a Promise static method before syntax?

Yes but not exact same thing. So allSettled can be included the spreading fashion await!.. or something similar. race and any cannot handle by spread operator because they are conditional. They should choose only one item from the array of promises.

I have an idea for race and any apart from the spread idea.


// const fastVal = await Promise.race(func1(), func2());
const fastVal = await ! (func1() | func2());
// or
const fastVal = await ! [func1() , func2()];

// const anyVal = await Promise.any(func1(), func2());
const anyVal = await ? (func1() | func2());
// or 
const anyVal = await ? [func1() , func2()];

Can you explain a little bit? Do you mean async context?

Thanks,
Tuğrul

No, I mean like Promise.spread or something, that can take an object with Promises as values - before adding syntax that can do that.

I don't think Promise.spread static function is necessary. But let me see if you have an idea

I think that no syntax proposal should be combining promises in a way that isn't already possible with .then or Promise static methods, which includes objects with promise-valued properties.

Actually you can write for your own Promise static methods. Do they have to be? Also other functionalities...

Please make my previous message visible.

I think we're talking past each other.

I'm saying that as a prerequisite for adding syntax that can await "an object with Promise values", there must first exist an API for it, just like await, and object spread.

@ljharb's suggestion makes sense. EcmaScript generally has a high syntax bar, they don't like adding new syntax left and right. So one way to "proove" that a particular syntax request is useful enough is to implement that request as a new API and see how strongly the community adopts it.

So, in this scenario, we would add a Promise.spread(), or Promise.allMembers(), or whatever to resolve all of the promises within an object. If it turns out this feature is being used everywhere you look, then they might consider adding a syntactic version to make it easier to read.

For arrays / iterables, i think await.all is more clear, and even then I'm not convinced new syntax is justified given that await Promise.all() works just as well.

For object likes, I agree there should first be an API to do this before considering syntax. When we informally discussed this in the past, it wasn't obvious to me that a plain object is always what's wanted. I've actually used a more verbose but more versatile Promise.allEntries. Promise.allEntries · GitHub

1 Like

There is a little confusion. This feature is not target to replace Promise static methods.

The feature is await version of ... and it is making Promise.all logic occasionally. Please consider in this perspective.

sync version of spread

stage 1

const first = getFirstSync();
const second = getSecondSync();

const values = [...[first, second], ...[3, 4]];

stage 2

const values = [...[getFirstSync(), getSecondSync()], ...[3, 4]];

async version of spread

stage 1

const first = getFirstAsync();
const second = getSecondAsync();

const values = [...[await first, await second], ...[3, 4]];

stage 2

const values = [await...[getFirstAsync(), getSecondAsync()], ...[3, 4]];
const values = [...await Promise.all([getFirstAsync(), getSecondAsync()]), ...[3, 4]];
const values = [...await.all [getFirstAsync(), getSecondAsync()], ...[3, 4]];

When considering arrays only, I do not see any case where your await... cannot be substituted by ...await.all

To be honest, I would probably write those avoiding spread altogether:

const values = await Promise.all([getFirstAsync(), getSecondAsync(), 3, 4]);
const values = await.all [getFirstAsync(), getSecondAsync(), 3, 4];
1 Like

Yeah, I'd say over 90% of my uses have been one of two things:

  1. Starting a relatively small constant number of tasks concurrently and awaiting their results
  2. Iterating an array of tasks and performing all of them maximally parallel without regard for their return value (though I've been doing this less and less lately as it tends to interfere with the throughput of other tasks)

For what it’s worth, there is the Array.fromAsync proposal that would serve as the sequential version of Promise.all. I was imagining that it would set up the machinery for a future await ...x syntax that would be equivalent to ...await Array.fromAsync(x), although the latter would just be a syntactic nicety that perhaps avoids an unnecessary array allocation.