p-map
- Version 7.1.1
- Published
- 67.9 kB
- No dependencies
- MIT license
Install
npm i p-mapyarn add p-mappnpm add p-mapOverview
Map over promises concurrently
Index
Variables
variable pMapSkip
const pMapSkip: Symbol;Return this value from a
mapperfunction to skip including the value in the returned array, or, forpMapKeyedandpMapSettledKeyed, to leave out the key.Example 1
import pMap, {pMapSkip} from 'p-map';import got from 'got';const sites = [getWebsiteFromUsername('sindresorhus'), //=> Promise'https://avajs.dev','https://example.invalid','https://github.com'];const mapper = async site => {try {const {requestUrl} = await got.head(site);return requestUrl;} catch {return pMapSkip;}};const result = await pMap(sites, mapper, {concurrency: 2});console.log(result);//=> ['https://sindresorhus.com/', 'https://avajs.dev/', 'https://github.com/']
variable pMapStop
const pMapStop: Symbol;Return this value from a
mapperfunction to stop iterating, likebreakin a loop.pMapresolves with the results of the elements before it, in order, without waiting for the elements after it. Like in a loop, an error from an earlier element still rejects. An error from a later element rejects only if it happens before the stop. WithstopOnError: false, only the errors from earlier elements are collected.pMapKeyedstops the same way, and keeps only the keys before it.pMapSettledandpMapSettledKeyedalso stop the same way, but an error from an element before the stop gives a{status: 'rejected', reason}result instead of a rejection.pMapIterableends the stream where the stop would have been yielded: after the elements before it withpreserveOrder, or after the results that were ready before it without.pMap,pMapSettled, andpMapIterablethen read no more elements frominput, and closeinput.pMapKeyedandpMapSettledKeyedhave read all the values already. Mappers that are still running are not canceled, and their results are dropped. The element that returnspMapStopadds no value to the result.Example 1
import pMap, {pMapStop} from 'p-map';function * pageNumbers() {for (let pageNumber = 1; ; pageNumber++) {yield pageNumber;}}const mapper = async pageNumber => {const page = await getPage(pageNumber);return page.items.length === 0 ? pMapStop : page;};const pages = await pMap(pageNumbers(), mapper, {concurrency: 4});console.log(pages);//=> Every page before the first empty page, in order
Functions
function pMap
pMap: <Element, NewElement>( input: | AsyncIterable<Element | Promise<Element>> | Iterable<Element | Promise<Element>>, mapper: Mapper<Element, NewElement>, options?: Options) => Promise<Array<Exclude<NewElement, Control>>>;Parameter input
Synchronous or asynchronous iterable that is iterated over concurrently, calling the
mapperfunction for each element. Each iterated item isawait'd before themapperis invoked so the iterable may return aPromisethat resolves to an item. Asynchronous iterables (different from synchronous iterables that returnPromisethat resolves to an item) can be used when the next item may not be ready without waiting for an asynchronous process to complete and/or the end of the iterable may be reached after the asynchronous process completes. For example, reading from a remote queue when the queue has reached empty, or reading lines from a stream.Parameter mapper
Function which is called for every item in
input. Expected to return aPromiseor value.Returns
A
Promisethat is fulfilled when all promises ininputand the ones returned frommapperare fulfilled, or rejects if any of the promises reject. The fulfilled value is anArrayof the fulfilled values returned frommapperininputorder.Example 1
import pMap from 'p-map';import got from 'got';const sites = [getWebsiteFromUsername('sindresorhus'), //=> Promise'https://avajs.dev','https://github.com'];const mapper = async site => {const {requestUrl} = await got.head(site);return requestUrl;};const result = await pMap(sites, mapper, {concurrency: 2});console.log(result);//=> ['https://sindresorhus.com/', 'https://avajs.dev/', 'https://github.com/']
function pMapIterable
pMapIterable: <Element, NewElement>( input: | AsyncIterable<Element | Promise<Element>> | Iterable<Element | Promise<Element>>, mapper: Mapper<Element, NewElement>, options?: IterableOptions) => AsyncIterable<Exclude<NewElement, Control>>;Like an async generator, a
return()orthrow()on the iterator that comes while anext()call is still pending waits for thatnext()to settle. Abreakin afor awaitloop is not affected, as the loop only stops between results. Ifinputcan block innext()for good, like a queue that waits for an item, stop it at the source, for example with anAbortSignalthat it listens to.The iterable itself has no
Symbol.asyncDispose, soawait usingon it throws aTypeError, and it can be iterated again, so there is no one iteration it could dispose. To get the cleanup ofawait usingwithout afor awaitloop, apply it to the iterator from[Symbol.asyncIterator](); on runtimes where async generators haveSymbol.asyncDispose, closing that iterator closes the source, like on a real async generator.Parameter input
Synchronous or asynchronous iterable that is iterated over concurrently, calling the
mapperfunction for each element. Each iterated item isawait'd before themapperis invoked so the iterable may return aPromisethat resolves to an item. Asynchronous iterables (different from synchronous iterables that returnPromisethat resolves to an item) can be used when the next item may not be ready without waiting for an asynchronous process to complete and/or the end of the iterable may be reached after the asynchronous process completes. For example, reading from a remote queue when the queue has reached empty, or reading lines from a stream.Parameter mapper
Function which is called for every item in
input. Expected to return aPromiseor value.Returns
An async iterable that streams each return value from
mapperin order, or as soon as each is ready whenpreserveOrderisfalse.Example 1
import {pMapIterable} from 'p-map';// Multiple posts are fetched concurrently, with limited concurrency and backpressurefor await (const post of pMapIterable(postIds, getPostMetadata, {concurrency: 8})) {console.log(post);};
function pMapKeyed
pMapKeyed: <Input extends object, NewValue extends KeyedNewValue>( input: KeyedInput<Input>, mapper: KeyedMapperFunction<Input, NewValue>, options?: Options) => Promise<KeyedResult<Input, NewValue, Exclude<NewValue, Control>>>;A version of
pMapfor the values of an object or aMap, like [Promise.allKeyed()](https://github.com/tc39/proposal-await-dictionary) is forPromise.all().For an object, it uses the own enumerable keys, strings and symbols, like
Promise.allKeyed(). For aMap, it uses the entries, and a key can be any value. AMapfrom another realm, like fromnode:vmor an iframe, is used as an object, so its entries are not mapped. All the values are read right away, and each value isawait'd beforemapperis called for it, so a value may be aPromise. With TypeScript, give aninputof typeany, like the result ofresponse.json(), a specific type, likeas Record<string, string>, as the result type is not useful otherwise.A value that rejects gets a handler right away, so it is never an unhandled rejection, even when
concurrencyhas not reached it yet.A
pMapSkipresult leaves out the key, andpMapStopkeeps only the keys before it.It takes the same options as
pMap.Parameter input
An object or a
Mapwhose values are mapped.Parameter mapper
Function which is called with each value and its key. Expected to return a
Promiseor value.Returns
A
Promisethat is fulfilled with an object with the same keys, in the same order, and the values returned frommapper, or rejects if any of the values or the mappers reject. The object has anullprototype, like the one fromPromise.allKeyed(). For aMap, it is a newMap.Example 1
import {pMapKeyed} from 'p-map';const {user, posts} = await pMapKeyed({user: 'https://example.com/api/user',posts: 'https://example.com/api/posts',}, async url => {const response = await fetch(url);return response.json();}, {concurrency: 2});
function pMapSettled
pMapSettled: <Element, NewElement>( input: | AsyncIterable<Element | Promise<Element>> | Iterable<Element | Promise<Element>>, mapper: Mapper<Element, NewElement>, options?: SettledOptions) => Promise<Array<PromiseSettledResult<Exclude<NewElement, Control>>>>;A version of
pMapfor [Promise.allSettled()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled): an error frommapper, or an element ofinputthat rejects, does not reject the returnedPromise.An element of
inputthat rejects gets a{status: 'rejected', reason}result, andmapperis not called for it. ApMapSkipresult is left out, andpMapStopstops like inpMap.The returned
Promisestill rejects when iteratinginputthrows, likePromise.allSettled(), and when thesignalaborts.It takes the same options as
pMap, exceptstopOnError.Promises that are already in
inputare already running, soconcurrencycannot limit them. With a finiteconcurrency, a promise that rejects beforepMapSettledreaches it is reported as an unhandled rejection. For promises you already have, usePromise.allSettled(). WithpMapSettled, give the values ininputand start the async work inmapper.Parameter input
Synchronous or asynchronous iterable that is iterated over concurrently, calling the
mapperfunction for each element. Each iterated item isawait'd before themapperis invoked so the iterable may return aPromisethat resolves to an item. Asynchronous iterables (different from synchronous iterables that returnPromisethat resolves to an item) can be used when the next item may not be ready without waiting for an asynchronous process to complete and/or the end of the iterable may be reached after the asynchronous process completes. For example, reading from a remote queue when the queue has reached empty, or reading lines from a stream.Parameter mapper
Function which is called for every item in
input. Expected to return aPromiseor value.Returns
A
Promisethat is fulfilled when all promises ininputand the ones returned frommapperare settled. The fulfilled value is anArrayof objects ininputorder, the same as fromPromise.allSettled():{status: 'fulfilled', value}for each value returned frommapper, and{status: 'rejected', reason}for each error frommapperor frominput.Example 1
import {pMapSettled} from 'p-map';const results = await pMapSettled(urls, async url => {const response = await fetch(url);return response.json();}, {concurrency: 4});for (const result of results) {if (result.status === 'fulfilled') {console.log(result.value);} else {console.error(result.reason);}}
function pMapSettledKeyed
pMapSettledKeyed: <Input extends object, NewValue extends KeyedNewValue>( input: KeyedInput<Input>, mapper: KeyedMapperFunction<Input, NewValue>, options?: SettledOptions) => Promise< KeyedResult<Input, NewValue, PromiseSettledResult<Exclude<NewValue, Control>>>>;A version of
pMapKeyedfor [Promise.allSettledKeyed()](https://github.com/tc39/proposal-await-dictionary): an error frommapper, or a value ofinputthat rejects, does not reject the returnedPromise.It takes the same
inputandmapperaspMapKeyed, and the same options aspMap, exceptstopOnError.A value of
inputthat rejects gets a{status: 'rejected', reason}result, andmapperis not called for it. Each value gets a handler right away, so it is never an unhandled rejection. ApMapSkipresult leaves out the key, andpMapStopkeeps only the keys before it.The returned
Promisestill rejects when readinginputthrows, and when thesignalaborts.Parameter input
An object or a
Mapwhose values are mapped.Parameter mapper
Function which is called with each value and its key. Expected to return a
Promiseor value.Returns
A
Promisethat is fulfilled with an object with the same keys, in the same order, when all the values and mappers are settled. Each value is{status: 'fulfilled', value}with the value returned frommapper, or{status: 'rejected', reason}with the error frommapperor frominput, the same as fromPromise.allSettledKeyed(). The object has anullprototype. For aMap, it is a newMap.Example 1
import {pMapSettledKeyed} from 'p-map';const {user, posts} = await pMapSettledKeyed({user: 'https://example.com/api/user',posts: 'https://example.com/api/posts',}, async url => {const response = await fetch(url);return response.json();}, {concurrency: 2});if (user.status === 'fulfilled') {console.log(user.value);}if (posts.status === 'rejected') {console.error(posts.reason);}
Type Aliases
type BaseOptions
type BaseOptions = { /** Number of concurrently pending promises returned by `mapper`.
Must be an integer from 1 and up or `Infinity`.
The right value depends on the work. Rules of thumb: - Network or database: the pool size or rate limit of the other side. - File system: tens to low hundreds, to avoid `EMFILE` errors. - Child processes or worker threads: [`os.availableParallelism()`](https://nodejs.org/api/os.html#osavailableparallelism). - Synchronous CPU-bound work: concurrency does not help.
If unsure, start low and measure. See also the “Dynamic concurrency” recipe in the readme.
`pMap` and `pMapSettled` can drop items that pulls from `input` already had in flight: when they stop early, because a mapper returns `pMapStop`, a mapper throws (only for `pMap`), or the `signal` aborts, and, with `concurrency` above 1, when one pull reports `done` while another still gets an item. That is invisible for a re-readable input, like an array or a string, but a source that cannot be re-read, such as a queue, loses those items. With `concurrency: 1`, only an abort can drop an item.
@default Infinity */ readonly concurrency?: number;};type Control
type Control = typeof pMapSkip | typeof pMapStop;type IterableOptions
type IterableOptions = BaseOptions & { /** Maximum number of elements taken from `input` that the consumer of the async iterable has not collected yet. That counts the elements being read, waiting for `mapper`, being mapped, and the results waiting to be collected. Calls to `mapper` will be limited so that there is never too much backpressure.
Must be an integer from `concurrency` and up or `Infinity`.
Useful whenever you are consuming the iterable slower than what the mapper function can produce concurrently. For example, to avoid making an overwhelming number of HTTP requests if you are saving each of the results to a database.
A `backpressure` above `concurrency` also lets `pMapIterable` read ahead: up to `backpressure - concurrency` elements, but no more than `concurrency`, are read from `input` while the mappers run, so a slow `input` does not leave a mapper waiting for its next element. Useful when reading `input` is slow, for example when it is another `pMapIterable`. With `concurrency: 1`, `backpressure: 2` overlaps reading each element with mapping the one before it. When the iteration ends early, the elements read ahead are not mapped, so a source that cannot be re-read, such as a queue, loses them.
A result of `pMapSkip` is collected by the consumer stepping over it, so it counts towards the limit until then. A mapper that skips most elements therefore still reads no further ahead than `backpressure` allows.
`backpressure` defaults to `concurrency`, which defaults to `Infinity`, so by default nothing bounds how far `input` is read ahead of the consumer. A source that never ends is then read without limit until memory runs out. Give such a source a finite `concurrency`. That also bounds `backpressure`, since it defaults to `concurrency`.
Default: `options.concurrency` */ readonly backpressure?: number;
/** Whether to yield the results in `input` order.
When `false`, each result is yielded as soon as it is ready. A slow element then no longer holds back the results after it, and those results no longer fill up `backpressure` while they wait, so `mapper` keeps running at full `concurrency`. Use it when the order of the results does not matter.
An error from `mapper` is then also thrown as soon as it happens, instead of after the results before it. The `index` passed to `mapper` is still the position in `input`.
Default: `true`
@example ``` import {pMapIterable} from 'p-map';
// Each page is saved as soon as it is downloaded, without waiting for slower pages before it for await (const page of pMapIterable(urls, downloadPage, {concurrency: 8, preserveOrder: false})) { await savePage(page); } ``` */ readonly preserveOrder?: boolean;};type KeyedInput
type KeyedInput<Input> = Input & (ReadonlyMap<unknown, unknown> | { readonly [Symbol.iterator]?: never });type KeyedKey
type KeyedKey<Input> = Input extends ReadonlyMap<infer Key, unknown> ? Key : Exclude<keyof Input, number> | `${Extract<keyof Input, number>}`;type KeyedMapper
type KeyedMapper< Input extends object = any, NewValue = unknown> = KeyedMapperFunction<Input, NewValue | Control>;Function which is called for every value in
input. Expected to return aPromiseor value.Parameter value
The value,
await'd.Parameter key
The key of the value.
type KeyedMapperFunction
type KeyedMapperFunction<Input, NewValue> = ( value: KeyedValue<Input>, key: KeyedKey<Input>) => MaybePromise<NewValue>;type KeyedNewValue
type KeyedNewValue = {} | null | undefined | Control;type KeyedResult
type KeyedResult<Input, NewValue, Value> = Input extends ReadonlyMap< infer Key, unknown> ? Map<Key, Value> : [NewValue] extends [Exclude<NewValue, Control>] ? { -readonly [Key in keyof Input]: Value } : { -readonly [Key in keyof Input]?: Value };type KeyedValue
type KeyedValue<Input> = Awaited< Input extends ReadonlyMap<unknown, infer Value> ? Value : Input[keyof Input]>;type Mapper
type Mapper<Element = any, NewElement = unknown> = ( element: Element, index: number) => MaybePromise<NewElement | Control>;Function which is called for every item in
input. Expected to return aPromiseor value.Parameter element
Iterated element.
Parameter index
Index of the element in the source array.
type MaybePromise
type MaybePromise<T> = T | Promise<T>;type Options
type Options = BaseOptions & { /** When `true`, the first mapper rejection will be rejected back to the consumer.
When `false`, instead of stopping when a promise rejects, it will wait for all the promises to settle and then reject with an [`AggregateError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) containing all the errors from the rejected promises.
The errors are listed in the order of the input, not in the order the promises happened to settle in, so the same input always produces the same `AggregateError`.
Caveat: When `true`, any already-started async mappers will continue to run until they resolve or reject. In the case of infinite concurrency with sync iterables, *all* mappers are invoked on startup and will continue after the first rejection. Use the `signal` option for abort control.
@default true */ readonly stopOnError?: boolean;
/** You can abort the promises using [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
An abort that comes from a timer or an I/O callback, like a `setTimeout`, cannot take effect while the mapping is inside a stretch of work that never waits on a timer or I/O. Draining a large input with mappers that just return a value is one such stretch, and there the run finishes first. This is the same for `Promise.all` and for a plain loop, and it goes away as soon as the mapper or the source waits on a timer or I/O.
@example ``` import pMap from 'p-map'; import delay from 'delay';
const abortController = new AbortController();
setTimeout(() => { abortController.abort(); }, 500);
const mapper = async value => value;
await pMap([delay(1000), delay(1000)], mapper, {signal: abortController.signal}); // Throws AbortError (DOMException) after 500 ms. ``` */ readonly signal?: AbortSignal | undefined;};type SettledOptions
type SettledOptions = Omit<Options, 'stopOnError'>;The options of
pMapSettledandpMapSettledKeyed: those ofpMap, exceptstopOnError, as they never reject for an error frommapper.
Package Files (1)
Dependencies (0)
No dependencies.
Dev Dependencies (8)
Peer Dependencies (0)
No peer dependencies.
Badge
To add a badge like this oneto your package's README, use the codes available below.
You may also use Shields.io to create a custom badge linking to https://www.jsdocs.io/package/p-map.
- Markdown[](https://www.jsdocs.io/package/p-map)
- HTML<a href="https://www.jsdocs.io/package/p-map"><img src="https://img.shields.io/badge/jsDocs.io-reference-blue" alt="jsDocs.io"></a>
- Updated .
Package analyzed in 1484 ms. - Missing or incorrect documentation? Open an issue for this package.
