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

