UNPKG

6.29 kBTypeScriptView Raw
1type BaseOptions = {
2 /**
3 Number of concurrently pending promises returned by `mapper`.
4
5 Must be an integer from 1 and up or `Infinity`.
6
7 @default Infinity
8 */
9 readonly concurrency?: number;
10};
11
12export type Options = BaseOptions & {
13 /**
14 When `true`, the first mapper rejection will be rejected back to the consumer.
15
16 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.
17
18 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. [Issue #51](https://github.com/sindresorhus/p-map/issues/51) can be implemented for abort control.
19
20 @default true
21 */
22 readonly stopOnError?: boolean;
23
24 /**
25 You can abort the promises using [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
26
27 @example
28 ```
29 import pMap from 'p-map';
30 import delay from 'delay';
31
32 const abortController = new AbortController();
33
34 setTimeout(() => {
35 abortController.abort();
36 }, 500);
37
38 const mapper = async value => value;
39
40 await pMap([delay(1000), delay(1000)], mapper, {signal: abortController.signal});
41 // Throws AbortError (DOMException) after 500 ms.
42 ```
43 */
44 readonly signal?: AbortSignal;
45};
46
47export type IterableOptions = BaseOptions & {
48 /**
49 Maximum number of promises returned by `mapper` that have resolved but not yet collected by the consumer of the async iterable. Calls to `mapper` will be limited so that there is never too much backpressure.
50
51 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.
52
53 Default: `options.concurrency`
54 */
55 readonly backpressure?: number;
56};
57
58type MaybePromise<T> = T | Promise<T>;
59
60/**
61Function which is called for every item in `input`. Expected to return a `Promise` or value.
62
63@param element - Iterated element.
64@param index - Index of the element in the source array.
65*/
66export type Mapper<Element = any, NewElement = unknown> = (
67 element: Element,
68 index: number
69) => MaybePromise<NewElement | typeof pMapSkip>;
70
71/**
72@param input - Synchronous or asynchronous iterable that is iterated over concurrently, calling the `mapper` function for each element. Each iterated item is `await`'d before the `mapper` is invoked so the iterable may return a `Promise` that resolves to an item. Asynchronous iterables (different from synchronous iterables that return `Promise` that 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.
73@param mapper - Function which is called for every item in `input`. Expected to return a `Promise` or value.
74@returns A `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled, or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned from `mapper` in `input` order.
75
76@example
77```
78import pMap from 'p-map';
79import got from 'got';
80
81const sites = [
82 getWebsiteFromUsername('sindresorhus'), //=> Promise
83 'https://avajs.dev',
84 'https://github.com'
85];
86
87const mapper = async site => {
88 const {requestUrl} = await got.head(site);
89 return requestUrl;
90};
91
92const result = await pMap(sites, mapper, {concurrency: 2});
93
94console.log(result);
95//=> ['https://sindresorhus.com/', 'https://avajs.dev/', 'https://github.com/']
96```
97*/
98export default function pMap<Element, NewElement>(
99 input: AsyncIterable<Element | Promise<Element>> | Iterable<Element | Promise<Element>>,
100 mapper: Mapper<Element, NewElement>,
101 options?: Options
102): Promise<Array<Exclude<NewElement, typeof pMapSkip>>>;
103
104/**
105@param input - Synchronous or asynchronous iterable that is iterated over concurrently, calling the `mapper` function for each element. Each iterated item is `await`'d before the `mapper` is invoked so the iterable may return a `Promise` that resolves to an item. Asynchronous iterables (different from synchronous iterables that return `Promise` that 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.
106@param mapper - Function which is called for every item in `input`. Expected to return a `Promise` or value.
107@returns An async iterable that streams each return value from `mapper` in order.
108
109@example
110```
111import {pMapIterable} from 'p-map';
112
113// Multiple posts are fetched concurrently, with limited concurrency and backpressure
114for await (const post of pMapIterable(postIds, getPostMetadata, {concurrency: 8})) {
115 console.log(post);
116};
117```
118*/
119export function pMapIterable<Element, NewElement>(
120 input: AsyncIterable<Element | Promise<Element>> | Iterable<Element | Promise<Element>>,
121 mapper: Mapper<Element, NewElement>,
122 options?: IterableOptions
123): AsyncIterable<Exclude<NewElement, typeof pMapSkip>>;
124
125/**
126Return this value from a `mapper` function to skip including the value in the returned array.
127
128@example
129```
130import pMap, {pMapSkip} from 'p-map';
131import got from 'got';
132
133const sites = [
134 getWebsiteFromUsername('sindresorhus'), //=> Promise
135 'https://avajs.dev',
136 'https://example.invalid',
137 'https://github.com'
138];
139
140const mapper = async site => {
141 try {
142 const {requestUrl} = await got.head(site);
143 return requestUrl;
144 } catch {
145 return pMapSkip;
146 }
147};
148
149const result = await pMap(sites, mapper, {concurrency: 2});
150
151console.log(result);
152//=> ['https://sindresorhus.com/', 'https://avajs.dev/', 'https://github.com/']
153```
154*/
155export const pMapSkip: unique symbol;