Also, wouldn't this be better formulated in terms of tasks and not
promises? Tasks could be decoupled from list iteration, for one.

On Sat, Sep 7, 2019 at 14:28 Cyril Auburtin <[email protected]>
wrote:

> It should really be in the form of a  static method like `Promise.map` or
> some other naming
>
> On Sat, Sep 7, 2019 at 6:40 PM Tom Boutell <[email protected]> wrote:
>
>> 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
>>
> _______________________________________________
> es-discuss mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/es-discuss
>
-- 
-----

Isiah Meadows
[email protected]
www.isiahmeadows.com
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to