Up to five instances of the loop body would be in progress, assuming at
least one of them awaits at some point. any await inside the loop body
would be respected with regard to code that follows it in the loop body.
The only place concurrency comes into play is that more than one of these
loopbodies could be in progress for separate items, for instance they could
all be awaiting  a long database operation or API call. To avoid the
frequent problems that come up with unlimited concurrency when dealing with
apis and similar, you set the concurrency so that you don't exceed those
reasonable limits.

On Sat, Sep 7, 2019, 12:24 PM Bob Myers <[email protected]> wrote:

> I don't understand how this would work.
>
> ```
> for (const thing of things concurrency 5) {
>   const result = await thing();
>   console.log(result); // <== what is `result` here, if the call to
> thing() hasn't completed?
> }
> ```
>
> Also, it's intellectually unsatisfying that I can't specify concurrency
> for all the async calls in
>
> ```
> await foo();
> await bar();
> for (const thing of things) await thing();
> await baz();
> ```
>
> Bob
>
>
>
> On Sat, Sep 7, 2019 at 8:17 AM Tom Boutell <[email protected]> wrote:
>
>> *REVISED PROPOSAL (thanks for the input so far!)*
>>
>> *Background*
>>
>> Developers learning async programming in the modern async/await era
>> frequently discover this useful pattern:
>>
>> ```js
>> for (item of items) {
>>   await db.insert(item);
>>   // additional awaited operations, etc.
>> }
>> ```
>>
>> This pattern extends the readability of "await" to cases where each item
>> in an array, or each item in an iterable, requires some asynchronous
>> processing. It also ensures that items are processed one at a time,
>> avoiding unbounded concurrency that results in excessive stress on back
>> ends, triggers API rate limiting, and otherwise results in unpredictable
>> bugs.
>>
>> However, a common next step is to wish for a manageable level of
>> concurrency. For instance, processing 500 asynchronous calls at once is
>> unwise, especially in a web application that is already handling 100
>> requests at once. But, processing 5 at once may be reasonable and improve
>> the processing time per request.
>>
>> Unfortunately, at present, this requires shifting mental gears from
>> async/await to promises. Here is an example based on Bluebird, there are of
>> course other libraries for this:
>>
>> ```js
>> const Promise = require('bluebird');
>> await Promise.map(items, async function(item) {
>>   await db.insert(item);
>>   // additional awaited operations, etc.
>> }, *{ concurrency: 5 }*);
>> ```
>>
>> While effective, this is a lot of boilerplate and a shift of mental
>> model. And in my experience as a mentor to many developers, this is *the
>> only situation in which they frequently need to reach for a promise
>> library. *A language feature to naturally integrate it with async/await
>> would substantially expand the effectiveness of async/await as a tool for
>> reducing the cognitive load of asynchronous programming.
>>
>> *Proposed Feature*
>>
>> I propose extending the existing async / await syntax to accommodate 
>> *specifying
>> the concurrency of a for...of loop:*
>>
>> ```js
>> for (item of items *concurrency 5*) {
>>   // db.insert is an async function
>>   await db.insert(item);
>> }
>> console.log('Processing Complete');
>> ```
>>
>> The major benefit here is that *the developer does not have to shift
>> gears mentally from async/await to thinking about promises to deal with a
>> common case in systems programming. *They are able to continue with the
>> pattern they are already comfortable with.
>>
>> Up to 5 loop bodies commence concurrently with regard to "await"
>> statements (see below).
>>
>> There is no guarantee that item 3 will finish before item 2, or that item
>> 4 won't start (due to 3 being finished) before item 2 ends, etc.
>>
>> If an exception is not caught inside the loop body, the loop stops, that
>> exception is thrown beyond the loop, and any further exceptions from that
>> invocation of the loop due to concurrently executing loop bodies are
>> discarded.
>>
>> Just as with an ordinary "for...of" loop containing an "await" statement, *it
>> is guaranteed that, barring an exception, the loop body will execute
>> completely for every item in "items" before the loop exits and the
>> console.log statement executes.* The only difference is that *the
>> specified amount of concurrency is permitted during the loop*.
>>
>> "5" may be any expression resulting in a number. It is cast to an
>> integer. If  the result is not a natural number, an error is thrown (it
>> must not be 0 or a negative number).
>>
>> *FAQs*
>>
>> *"What if I want unlimited concurrency?"*
>>
>> It is rarely a good idea. It results in excessive stress on back ends,
>> unnecessary guards that force serialization in interface libraries just to
>> cope with (and effectively negate) it, and API rate limiting. This feature
>> teaches the best practice that the level of concurrency should be mindfully
>> chosen. However, those who really want it can specify "concurrency
>> items.length" or similar.
>>
>> *"What about async iterators?"*
>>
>> The feature should also be supported here:
>>
>> ```js
>> for *async* (item of items *concurrency 5*) {
>>   // db.insert is an async function
>>   await db.insert(item);
>> }
>> ```
>>
>> While the async iterator itself is still sequential rather than
>> concurrent, frequently these can supply values considerably faster than
>> they are processed by the loop body, and so there is still potential
>> benefit in having several items "in the hopper" (up to the concurrency
>> limit) at a time.
>>
>> --
>> Chief Software Architect
>> Apostrophe Technologies
>> Pronouns: he / him / his
>> _______________________________________________
>> es-discuss mailing list
>> [email protected]
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to