Proposal: `await.all {...}` for parallelism

Naveen Chawla naveen.chwl at gmail.com
Wed Nov 20 12:43:15 UTC 2019


I don't like the idea of await behaving differently inside vs outside of
the "await.all" block, and I think is a source of bugs:

await.all {
    const x = await doSomethingAsync();
    //x is still undefined here! Not the case outside of an await.all block
}

Maybe if you drop the "await" in your example:

await.all {
    const x = doSomethingAsync();
    //x is just the promise here, but at least is the same whether inside
or outside of the await.all block
}

...but that still waits for the async functions to complete, I think it
would cause fewer bugs and would seem to still satisfy the motivation?

On Wed, 20 Nov 2019 at 09:06, Cyril Auburtin <cyril.auburtin at gmail.com>
wrote:

> There's `for await` loops since recently, there could be `await for` loops
> for wrapping the whole execution of a loop
>
> ```js
> console.time(1);
> await for (const fn of [()=>delay(50).then(()=>'a'),
> ()=>delay(80).then(()=>'b')]) {
>   console.timeLog(1, await fn());
> }
> console.timeEnd(1);
> ```
>
> This would log the same than:
>
> ```js
> console.time(1);
> await Promise.all(
>   [()=>delay(50).then(()=>'a'), ()=>delay(80).then(()=>'b')]
>     .map(async fn => { console.timeLog(1, await fn()) })
> );
> console.timeEnd(1);
> /*
> 1: 51.066162109375ms a
> 1: 80.998291015625ms b
> 1: 81.315185546875ms
> */
> ```
>
> without `await for`, things are serial:
> ```js
> console.time(1);
> for (const fn of [()=>delay(50).then(()=>'a'),
> ()=>delay(80).then(()=>'b')]) {
>   console.timeLog(1, await fn());
> }
> console.timeEnd(1);
> /*
> 1: 50.68212890625ms a
> 1: 130.9951171875ms b
> 1: 131.1162109375ms
> */
> ```
>
> (`var delay = t => new Promise(r => setTimeout(r, t));`)
>
> On Wed, Nov 20, 2019 at 6:44 AM Jacob Bloom <mr.jacob.bloom at gmail.com>
> wrote:
>
>> Regarding parallel for-loops: I'd consider that a separate problem.
>> You'd want parallel for-loops for things like requests to the same
>> API, where each promise is handled the same way. `await.all` is more
>> for handling disparate tasks in parallel without having to resort to
>> thinking in terms of arrays and iteration.
>>
>> On Tue, Nov 19, 2019 at 10:27 PM Guy Bedford <guybedford at gmail.com>
>> wrote:
>> >
>> > Typically I find I want to loop over an iterator of items and apply a
>> function body of work on them in parallel.
>> >
>> > So it would be nice to support full blocks of statements that can do
>> this work in parallel, instead of relying on just expressions or functions
>> to achieve this.
>> >
>> > Extending for loops to have a parallel form is another option (I seem
>> to recall something similar brought up before here):
>> >
>> > ```
>> > for await.all (const entry of entries) {
>> >   await doWork(entry);
>> > }
>> > ```
>> >
>> > Whether async iteration should be supported or treated as sync or
>> parallel is another question though, and possibly a confusion of the form.
>> >
>> > On Tue, 19 Nov 2019 at 23:20, Jordan Harband <ljharb at gmail.com> wrote:
>> >>
>> >> If we have `await.all`, what about `await.race`, `await.allSettled`,
>> `await.any`?
>> >>
>> >> On Tue, Nov 19, 2019 at 7:45 PM Jacob Bloom <mr.jacob.bloom at gmail.com>
>> wrote:
>> >>>
>> >>> To simplify the problem of working with promises in parallel, I
>> >>> propose this new syntax:
>> >>>
>> >>> ```javascript
>> >>> async function initialize() {
>> >>>   let foo, bar, baz;
>> >>>   await.all {
>> >>>     foo = (await request('foo.json')).data;
>> >>>     bar = (await request('bar.json')).data;
>> >>>     baz = (await request('baz.json')).data;
>> >>>   }
>> >>>   render(foo, bar, baz);
>> >>> }
>> >>> ```
>> >>>
>> >>> Each child statement of the curly braces is evaluated in parallel and
>> >>> execution resumes when they've all resolved.
>> >>>
>> >>> **The Problem:** with current syntax, the above function would
>> >>> probably look something like this:
>> >>>
>> >>> ```javascript
>> >>> async function initialize() {
>> >>>   const [
>> >>>     { data: foo }, // renaming response.data => foo
>> >>>     { data: bar },
>> >>>     { data: baz },
>> >>>   ] = await Promise.all([
>> >>>     request('foo.json'),
>> >>>     request('bar.json'),
>> >>>     request('baz.json'),
>> >>>   ]);
>> >>>   render(foo, bar, baz);
>> >>> }
>> >>> ```
>> >>>
>> >>> For this kind of use case, `Promise.all` leads to "parallel lists" of
>> >>> promises and their return values, which must be kept in sync. Using
>> >>> those values either requires (sometimes deep) destructuring or
>> >>> temporary variables.
>> >>>
>> >>> This structure is also just fundamentally different from working
>> >>> serially in async/await and it forces you to reason about the problem
>> >>> in a specific way. This doesn't appear to be a conscious decision to
>> >>> force good code practices, it's just a limitation that falls naturally
>> >>> out of the current syntax. Thus, we have an opportunity to shift some
>> >>> of the burden back to the language with this new syntax.
>> >>>
>> >>> Here's the full proposal:
>> >>> https://github.com/mrjacobbloom/proposal-await-all -- let me know
>> what
>> >>> you think!
>> >>> _______________________________________________
>> >>> es-discuss mailing list
>> >>> es-discuss at mozilla.org
>> >>> https://mail.mozilla.org/listinfo/es-discuss
>> >>
>> >> _______________________________________________
>> >> es-discuss mailing list
>> >> es-discuss at mozilla.org
>> >> https://mail.mozilla.org/listinfo/es-discuss
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20191120/37756d5c/attachment.html>


More information about the es-discuss mailing list