p-map

repository·main·Indexed 23 days ago

https://github.com/sindresorhus/p-map

A utility for mapping over promises or iterables concurrently. Version 7.0.6 provides fine-grained control over concurrency, error handling, and backpressure. It includes pMap for returning a Promise that resolves to an Array, pMapIterable for streaming results via an async iterable, and pMapSkip for excluding specific elements from the final results.

Tokens
2.9K
Snippets
10
Records
14
Agent score
71%

What's inside p-map

  1. Configure pMap options

    main

    When using pMap or pMapIterable, you can provide an options object to control execution behavior:

    • concurrency (number): The number of concurrently pending promises returned by mapper. Defaults to Infinity. Minimum is 1.
    • stopOnError (boolean, pMap only): When true (default), the first mapper rejection will be rejected back to the consumer. When false, it waits for all promises to settle and rejects with an AggregateError containing all errors.
    • signal (AbortSignal, pMap only): Allows aborting the promises using an AbortController.
    • backpressure (number, pMapIterable only): The maximum number of promises returned by mapper that have resolved but not yet been collected by the consumer. Defaults to options.concurrency.
    // Example using signal to abort
    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.
  2. Implement rate limiting with p-map

    main

    To limit how often the mapper function is invoked (rate limiting), compose pMap with a rate limiter like p-throttle.

    import pThrottle from 'p-throttle';
    import pMap from 'p-map';
    
    const throttle = pThrottle({
    	limit: 1,
    	interval: 1000,
    	strict: true,
    });
    
    const result = await pMap(input, throttle(mapper), {concurrency: 2});
  3. Skip items in the result array using pMapSkip

    main

    If you want to exclude certain elements from the final result array, return pMapSkip from your mapper function. This is useful for filtering results during the mapping process without changing the input array.

    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/']
  4. Use pMap to map over promises concurrently

    main

    Use pMap(input, mapper, options?) to run promise-returning or async functions multiple times with different inputs concurrently. Unlike Promise.all(), you can control the concurrency level and decide how to handle errors. It returns a Promise that resolves to an Array of the fulfilled values in the original input order.

    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/']
  5. Use pMapIterable to stream results with backpressure

    main

    Use pMapIterable(input, mapper, options?) to return an async iterable that streams each return value from the mapper in order. This is useful for processing large datasets where you want to limit concurrency and manage backpressure.

    import {pMapIterable} from 'p-map';
    
    // Multiple posts are fetched concurrently, with limited concurrency and backpressure
    for await (const post of pMapIterable(postIds, getPostMetadata, {concurrency: 8})) {
    	console.log(post);
    };
  6. Configure pMapIterable options

    main

    When using pMapIterable, you can provide IterableOptions to control execution and backpressure:

    • concurrency: The number of concurrently pending promises. Defaults to options.concurrency.
    • backpressure: The maximum number of promises returned by mapper that have resolved but not yet been collected by the consumer. This limits calls to mapper to prevent overwhelming the consumer (e.g., if the consumer is saving results to a database slower than the mapper produces them).
  7. Use pMapIterable to stream results from an iterable

    main

    Use pMapIterable when you want to process results as they become available via an async iterable. This is ideal for streaming data (e.g., reading lines from a stream or a remote queue) where you want to consume results one by one without waiting for the entire collection to be processed.

    import {pMapIterable} from 'p-map';
    
    // Multiple posts are fetched concurrently, with limited concurrency and backpressure
    for await (const post of pMapIterable(postIds, getPostMetadata, {concurrency: 8})) {
    	console.log(post);
    };
  8. Skip items in the result using pMapSkip

    main

    If you want to exclude certain items from the final result array (when using pMap) or the resulting async iterable (when using pMapIterable), return pMapSkip from your mapper function. This is useful for handling errors or filtering data during the mapping process.

    import pMap, {pMapSkip} from 'p-map';
    import got from 'got';
    
    const sites = [
    	getWebsiteFromUsername('sindresorhus'), //=> Promise
    	'https://avajs.dev',
    	'https://example.invalid',
    ];
    
    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/']
  9. Use pMap to map an iterable with concurrency control

    main

    The pMap function maps an Iterable or AsyncIterable to an array of results using a mapper function. It supports concurrency limiting and can be configured to stop on error or collect errors into an AggregateError.

    Parameters:

    • iterable: An Iterable or AsyncIterable to map.
    • mapper: A function that receives (element, index) and returns a promise or value.
    • options (optional):
      • concurrency: The maximum number of concurrent executions. Defaults to Number.POSITIVE_INFINITY.
      • stopOnError: If true (default), the promise rejects immediately when the mapper throws. If false, errors are collected and thrown as an AggregateError once the iteration is complete.
      • signal: An AbortSignal to cancel the operation.
  10. Use pMap to map an iterable to an array of promises

    main

    Use pMap to iterate over a synchronous or asynchronous iterable concurrently. It executes a mapper function for each element and returns a Promise that resolves to an Array of the results in the original order. This is useful for limiting concurrency when performing asynchronous tasks like HTTP requests.

    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/']
  11. Use pMapIterable to create an async generator with backpressure

    main

    The pMapIterable function returns an AsyncIterable that maps an input iterable using a mapper function. This is useful for processing large streams of data where you want to control how many items are being processed at once and how many are buffered.

    Parameters:

    • iterable: An Iterable or AsyncIterable to map.
    • mapper: A function that receives (element, index) and returns a promise or value.
    • options (optional):
      • concurrency: The maximum number of concurrent executions. Defaults to Number.POSITIVE_INFINITY.
      • backpressure: The maximum number of pending promises allowed in the buffer. Must be greater than or equal to concurrency. Defaults to concurrency.

    Behavior:

    • It yields values as they are completed by the mapper.
    • If the mapper returns pMapSkip, that value is omitted from the yielded results.