Map over promises concurrently

Overview

p-map

Map over promises concurrently

Useful when you need to run promise-returning & async functions multiple times with different inputs concurrently.

This is different from Promise.all() in that you can control the concurrency and also decide whether or not to stop iterating when there's an error.

Install

$ npm install p-map

Usage

import pMap from 'p-map';
import got from 'got';

const sites = [
	getWebsiteFromUsername('https://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/']

API

pMap(input, mapper, options?)

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.

input

Type: Iterable<Promise | unknown>

Iterated over concurrently in the mapper function.

mapper(element, index)

Type: Function

Expected to return a Promise or value.

options

Type: object

concurrency

Type: number (Integer)
Default: Infinity
Minimum: 1

Number of concurrently pending promises returned by mapper.

stopOnError

Type: boolean
Default: true

When set to false, instead of stopping when a promise rejects, it will wait for all the promises to settle and then reject with an aggregated error containing all the errors from the rejected promises.

p-map for enterprise

Available as part of the Tidelift Subscription.

The maintainers of p-map and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. Learn more.

Related

  • p-all - Run promise-returning & async functions concurrently with optional limited concurrency
  • p-filter - Filter promises concurrently
  • p-times - Run promise-returning & async functions a specific number of times concurrently
  • p-props - Like Promise.all() but for Map and Object
  • p-map-series - Map over promises serially
  • p-queue - Promise queue with concurrency control
  • More…
Comments
  • Add support for AsyncIterable as input

    Add support for AsyncIterable as input

    Overview

    • Expand capabilities to handle both async and sync iterables - Fixes #20

    Open Issues

    • [x] Duplicating the tests for the async versions doesn't feel right - Let me know if there is a better way to handle this with ava
    • [x] There is a problem in the original functionality around the stop-on-error test that needs to be resolved
      • The test has a bug in that neither p-map nor the test mapper function, which is provided for that specific test and is not the common version, await the calling of the delay() function for item 2
      • This means that item 2 will only ever return a Promise, never a value
      • When this is fixed to await the function call, it causes the returned results to change from [1, 3] to [1, 3, 2]
      • Fixing this test makes it clear that the concurrency setup loop does not wait for mappers, so the only way to make this test fail would be to have enough items that eventually the initial iteration could not reach the last items in the test array before the 100 ms delay on the exception expires
      • With concurrency = 1 this test behaves as expected since there are not unlimited unawaited promises created
      • Let me know your thoughts on how to resolve this as it becomes more apparent with the behavior changes needed for asyncIterable (where the concurrency setup iteration of asyncIterable has to be awaited to prevent inifinte runners from being created)
      • The test, in the state it's in in this PR, does not actually demonstrate that stop on error works as intended
    opened by huntharo 11
  • Support aborting the mapping

    Support aborting the mapping

    e.g. a few seconds into waiting for the promise to finish, we could increase concurrency due to CPU limit being lowered below 20%, to a concurrency of 5x or something. Basically dynamic concurrency

    enhancement help wanted 
    opened by niftylettuce 11
  • Must use import to load ES Module

    Must use import to load ES Module

    I bump my service which are using p-map for testing from version 4.0.0 to 5.0.0 and now I got the following issue during my test.

    node version v14.16.0

    Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: .../node_modules/p-map/index.js require() of ES modules is not supported. require() of .../node_modules/p-map/index.js from ..../tests/contracts/step_definitions/test.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules. Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from .../node_modules/p-map/package.json.

    is is a breaking change not documented? if yes how I can fix then

    note I use pMap using import

    import pMap from 'p-map';

    opened by SSANSH 9
  • `Must use import to load ES Module` (with typescript)

    `Must use import to load ES Module` (with typescript)

    Hello,

    How to use this library with typescript? I'm getting this error:

    Must use import to load ES Module: /home/omar/Desktop/node_modules/p-map/index.js\n' +
        'require() of ES modules is not supported.\n' +
        'require() of /home/omar/Desktop/node_modules/p-map/index.js from /home/omar/Desktop/src/resolvers/views.ts is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.\n' +
        'Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/omar/Desktop/node_modules/p-map/package.json.
    

    Here's my tsconfig:

    {
        "compilerOptions": {
            "target": "ES2018",
            "module": "CommonJS",
            "lib": [
                "es2020",
                "esnext.asynciterable"
            ],
            "experimentalDecorators": true,
            "emitDecoratorMetadata": true,
            "esModuleInterop": true,
            "outDir": "dist",
            "baseUrl": "src",
            "sourceMap": true,
            "skipLibCheck": true,
            "forceConsistentCasingInFileNames": true,
            "moduleResolution": "node",
            "removeComments": true,
        },
        "include": [
            "src/**/*.ts",
            "prisma/**/*.ts",
        ],
        "exclude": [
            "node_modules/**/*",
            "_warmup/**/*",
            ".vscode/**/*",
            ".husky/**/*",
            "dist/**/*"
        ],
    }
    
    opened by omar-dulaimi 6
  • Consider rejecting only on rejected Promises.

    Consider rejecting only on rejected Promises.

    According to the documentation, pMap 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.

    But strictly speaking, it's

    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, or mapper or options.concurrency are invalid, or mapper throws.

    It's a subtle difference, especially if you're awaiting pMap or passing an async function as mapper.

    opened by wtgtybhertgeghgtwtg 5
  • Provide `liftFn` to turn a fn into a promise resolution handler.

    Provide `liftFn` to turn a fn into a promise resolution handler.

    Hi @sindresorhus, I love your p-* libs use, but I find that most often, I want to be building interesting promise chains.

    getTimeNow().then( addTime("2 weeks")).then (lookupCalendar()).then(lookForConflicts).then(notify("email")) is the kind of promise based data-flow system that promises usually have me creating.

    The liftFn provided here allows for that fluent-style usage of p-map, taking the static elements- the mapper & whatever options- and lifting them into a handler that is called for each input.

    Promise.resolve([1,2,3]).then( pMap.liftFn( x=> x* 3).then( console.log) ought log [3,6,9].

    This vs:

    var input= Promise.resolve([1,2,3])
    var output= pMap( input, x=> x* 3).then( console.log)
    
    opened by rektide 4
  • Prevent some potential unhandled exceptions

    Prevent some potential unhandled exceptions

    • Source iterator next() functions can throw
    • There are 3 distinct cases where next() is called, one of which does not have a try/catch around it that will reject the outer promise, resulting in an unhandled promise rejection
    • Note: in the current state, the 3rd test fails - I'm not sure how you want to handle this... a try/catch for the entire next() function would handle it... but there are other ways, such as a try/catch within the catch...
    opened by huntharo 3
  • p-flat-map

    p-flat-map

    I encountered the need for p-flat-map. Here's what I came up with:

    const pFlatMap = async <Element, NewElements>(
      input: Iterable<Element>,
      mapper: pMap.Mapper<Element, NewElements>,
      options?: pMap.Options
    ): Promise<FlatArray<NewElements[], 1>[]> => {
      const mapped: NewElements[] = await pMap(input, mapper, options)
      return mapped.flat()
    }
    

    Usage example:

    const products = await pFlatMap(categories, listProductsForCategory, { concurrency: 50 })
    

    Would it be possible to add this to the collection?

    opened by MajorBreakfast 3
  • Alias for `Infinity`

    Alias for `Infinity`

    I happen to configure the concurrency option through JSON, but JSON cannot encode a Infinity value. Would you agree to taking 0 or -1 as an alias for Infinity?

    opened by silverwind 3
  • Undefined items added to resulting mapped collection

    Undefined items added to resulting mapped collection

    Random undefined items are added to my mapped array with version 1.1.0. I don't have the same issue with version 1.0.0 or with bluebird. I've been able to consistently reproduce the issue with the following test. The same test works with concurrency 1 or concurrency >= myInput.length.

    test('async with concurrency: 2', async t => {
    	const myInput = [100, 200, 10, 36, 13, 45];
    	const myMapper = value => {
    		return new Promise(resolve => {
    			setTimeout(() => resolve(value), value);
    		});
    	};
    
    	t.deepEqual(await m(myInput, myMapper, {concurrency: 2}), myInput);
    });
    

    It is not obvious to see the extra undefined items with the ava output (I've never used ava before) but my mocha/chai version of the test is showing this output:

    AssertionError: expected [ 100, 200, 10, , 36, , 13, , 45 ] to deeply equal [ 100, 200, 10, 36, 13, 45 ]
          + expected - actual
    
           [
             100
             200
             10
          -  [undefined]
             36
          -  [undefined]
             13
          -  [undefined]
             45
           ]
    
    
    opened by mlaflamm 3
  • Browser Compatibility with `^5.0.0`

    Browser Compatibility with `^5.0.0`

    After upgrading to ^5.0.0, vite got an error:

    browser-external:os:3 Uncaught Error: Module "os" has been externalized for browser compatibility and cannot be accessed in client code.
        at Object.get (browser-external:os:3:11)
        at index.js:6:27
    

    After some digging, this is related to aggregate-error ^4.0.0's dep clean-stack ^4.0.0

    import os from 'os' (index.js#L1)

    I wonder could homedir be implemented in a browser-friendly way?

    I don't know which repo is the most suitable place to open this issue, please transfer to the right place if needed.

    Thank you!

    opened by rwv 2
  • Add `pMapIterable`

    Add `pMapIterable`

    Main differences from pMap():

    • Skipped values are simply never yielded
    • stopOnError is not available because this can now be done by the user themselves
    • signal is also not available for the same reason
    • Values that are yielded from the iterator, are immediately passed to the mapper and the returned values are yielded from the function in the order that they originally were yielded

    If you're ok with this, I'll add docs and tests

    Fixes https://github.com/sindresorhus/promise-fun/issues/21

    opened by Richienb 0
  • Stack trace is lost from the point the code uses p-map

    Stack trace is lost from the point the code uses p-map

    Both, console.trace and throw new Error don't show the stack-trace beyond the point p-map got called. In other words, the functions that called before pMap, disappear from the stack trace. As a comparison, the p-map-series doesn't suffer from this issue. It does keep the stack-trace.

    See the example below, if you run a function that runs the native Promise.all, the stack trace shows the function name - runPromiseNative. Same if you run the function runPromisePmapSeries. However, try to run runPromisePmap, and you'll see how the stack trace truncated.

    I tried node v12.x and v14.x.

    const pMap = require('p-map');
    
    const pMapSeries = require('p-map-series');
    
    async function promiseFn() {
      throw new Error('stop')
    }
    
    async function runPromiseNative() {
      await Promise.all([promiseFn()]).then(() => { console.log('completed') }).catch((err) => console.error(err));
    }
    
    async function runPromisePmap() {
      await pMap([promiseFn], fn => fn()).then(() => { console.log('completed') }).catch((err) => console.error(err));
    }
    
    async function runPromisePmapSeries() {
      await pMapSeries([promiseFn], fn => fn()).then(() => { console.log('completed') }).catch((err) => console.error(err));
    }
    
    // runPromiseNative();
    
    runPromisePmap();
    
    // runPromisePmapSeries();
    

    Results when running runPromisePmap :

    Error: stop
        at promiseFn (/Users/davidfirst/teambit/bit/pmap.js:6:9)
        at /Users/davidfirst/teambit/bit/pmap.js:14:33
        at /Users/davidfirst/teambit/bit/node_modules/p-map/index.js:57:28
    

    Results when running runPromiseNative.

    Error: stop
        at promiseFn (/Users/davidfirst/teambit/bit/pmap.js:6:9)
        at runPromiseNative (/Users/davidfirst/teambit/bit/pmap.js:10:22)
        at Object.<anonymous> (/Users/davidfirst/teambit/bit/pmap.js:21:1)
        at Module._compile (internal/modules/cjs/loader.js:999:30)
        at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
        at Module.load (internal/modules/cjs/loader.js:863:32)
        at Function.Module._load (internal/modules/cjs/loader.js:708:14)
        at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
        at internal/main/run_main_module.js:17:47
    
    enhancement help wanted 
    opened by davidfirst 3
  • Allow breaking from iterator

    Allow breaking from iterator

    I wish I could stop the iteration early by returning something like pMap.stop (a Symbol) from the iterator.

    This is basically the same request as https://github.com/sindresorhus/p-each-series/issues/3

    For now, I have to throw an error on purpose just to break it. Thankfully, I don't need the return value of p-map anyway.

    But with this feature, the parts of the array that weren't computed yet could be set to undefined, or pMap.uncomputed (another Symbol), or even be specified by a valueForUncomputedEarlyStop option.

    Can I do a PR?

    enhancement help wanted 
    opened by papb 13
  • A way to set recommended/reasonable value for concurrency

    A way to set recommended/reasonable value for concurrency

    Do you have a module that calculates and exports a reasonable default value for concurrency? For example what is done in https://github.com/sindresorhus/got/pull/393. I'm planning to use p-map in some parts of nyc that can be async so I want to set a reasonable concurrency limit. I'd like to avoid calculating os.cpus().length multiple times and avoid duplicating the CI limiting logic.

    opened by coreyfarrell 9
Releases(v5.5.0)
  • v5.5.0(Jun 9, 2022)

  • v5.4.0(May 17, 2022)

  • v5.3.0(Nov 2, 2021)

  • v5.2.0(Oct 27, 2021)

    • Add support for AsyncIterable as input (#46) a24e909
    • Prevent some potential unhandled exceptions (#48) 11bc75d

    https://github.com/sindresorhus/p-map/compare/v5.1.0...v5.2.0

    Source code(tar.gz)
    Source code(zip)
  • v5.1.0(Jul 23, 2021)

    Improvements

    • Add the ability to skip an iteration (#39) c9c0882

    Fixes

    • Do not run mapping after stop-on-error happened (#40) 4b5f9e7

    https://github.com/sindresorhus/p-map/compare/v5.0.0...v5.1.0

    Source code(tar.gz)
    Source code(zip)
  • v5.0.0(Apr 17, 2021)

    Breaking

    • Require Node.js 12 dcdbc7a
    • This package is now pure ESM. Please read this.
    • AggregateError is no longer iterable. It moved to an .errors property.

    https://github.com/sindresorhus/p-map/compare/v4.0.0...v5.0.0

    Source code(tar.gz)
    Source code(zip)
  • v4.0.0(Mar 5, 2020)

    Breaking

    • Require Node.js 10 bf03769

    Improvements

    • Ensure concurrency option is an integer b342717

    https://github.com/sindresorhus/p-map/compare/v3.0.0...v4.0.0

    Source code(tar.gz)
    Source code(zip)
  • v3.0.0(Jul 13, 2019)

    Breaking:

    • Require Node.js 8 a200b62

    Enhancements:

    • Add stopOnError option (#16) 9f0b32f

    https://github.com/sindresorhus/p-map/compare/v2.1.0...v3.0.0

    Source code(tar.gz)
    Source code(zip)
  • v2.1.0(Apr 6, 2019)

Owner
Sindre Sorhus
Full-Time Open-Sourcerer. Wants more empathy & kindness in open source. Focuses on Swift & JavaScript. Makes macOS apps, CLI tools, npm packages. Likes unicorns
Sindre Sorhus
The ultimate generator based flow-control goodness for nodejs (supports thunks, promises, etc)

co Generator based control flow goodness for nodejs and the browser, using promises, letting you write non-blocking code in a nice-ish way. Co v4 co@4

TJ Holowaychuk 11.8k Jan 2, 2023
Helps you write libraries that accept both promises and callbacks.

What is it? promise-breaker makes it easy to write functions that will accept an optional callback, or return a Promise if a callback is not provided.

Jason Walton 83 Aug 11, 2022
P - Toolkit for managing multiple promises

@antfu/p Toolkit for managing multiple promises. Without const items = [1, 2, 3, 4, 5] (await Promise.all(items .map(async i => { const v = awa

Anthony Fu 284 Nov 24, 2022
Awesome Observable related stuff - An Observable is a collection that arrives over time.

Awesome Observables An Observable is a collection that arrives over time. Observables can be used to model push-based data sources such as events, tim

Sindre Sorhus 320 Dec 17, 2022
Map over an object in a preorder or postoder depth-first manner

obj-walker Walk objects like this guy. Map over an object in a preorder or postoder depth-first manner. Also, provides functions for serializing and d

David Sargeant 3 Jun 2, 2022
aka Scaletor, take screenshots of a piece of a map and scale/compare with other parts of the map

scale-a-tron A quick-and-dirty map that lets you compare one area to another. Draw a shape around a region, zoom in to another place on the map, and c

Stamen Design 24 Nov 7, 2022
This map is tracking the position of ISS(international space setallite) at every 1 second. I use Nasa's "where the iss" API and "Leaflet.js" for the map.

ISS-tracking-map About This map is tracking the position of ISS(international space setallite) at every 1 second. I use Nasa's "where the iss" API and

Waz.sheeran 2 Oct 25, 2021
Write JSX-driven components with functions, promises and generators.

Crank.js Write JSX-driven components with functions, promises and generators. Documentation is available at crank.js.org. Crank.js is in a beta phase,

null 2.5k Jan 1, 2023
:hourglass_flowing_sand: A higher order component for loading components with promises.

A higher order component for loading components with dynamic imports. Install yarn add react-loadable Example import Loadable from 'react-loadable'; i

Jamie Kyle 16.5k Jan 3, 2023
A solid, fast Promises/A+ and when() implementation, plus other async goodies.

when.js When.js is a rock solid, battle-tested Promises/A+ and when() implementation, including a complete ES6 Promise shim. It's a powerful combinati

The Javascript Architectural Toolkit 3.4k Dec 18, 2022
The ultimate generator based flow-control goodness for nodejs (supports thunks, promises, etc)

co Generator based control flow goodness for nodejs and the browser, using promises, letting you write non-blocking code in a nice-ish way. Co v4 co@4

TJ Holowaychuk 11.8k Jan 2, 2023
Helps you write libraries that accept both promises and callbacks.

What is it? promise-breaker makes it easy to write functions that will accept an optional callback, or return a Promise if a callback is not provided.

Jason Walton 83 Aug 11, 2022
Run async code one after another by scheduling promises.

promise-scheduler Run async code in a synchronous order by scheduling promises, with the possibility to cancel pending or active tasks. Optimized for

Matthias 2 Dec 17, 2021
P - Toolkit for managing multiple promises

@antfu/p Toolkit for managing multiple promises. Without const items = [1, 2, 3, 4, 5] (await Promise.all(items .map(async i => { const v = awa

Anthony Fu 284 Nov 24, 2022
Resolve parallel promises in key-value pairs whilst maintaining type information

async-kv Resolves promises in key-value pairs maintaining type information. Prerequisites NodeJS 12 or later Installation npm i async-kv yarn add asyn

Tony Tamplin 4 Feb 17, 2022
🐶 Learn JS Promises, with your friend 👑 Princess!

?? Learn JS Promises, with your friend ?? Princess!

Baylee Schmeisser 10 Jun 9, 2022
Converts an iterable, iterable of Promises, or async iterable into a Promise of an Array.

iterate-all A utility function that converts any of these: Iterable<T> Iterable<Promise<T>> AsyncIterable<T> AsyncIterable<Promise<T>> Into this: Prom

Lily Scott 8 Jun 7, 2022
Ajax library with XHR2, promises and request limit

qwest 4.5.0 ⚠ I finally decided to archive this repository. ⚠ At first, I developed Qwest because at the time other libraries were lacking of a proper

Aurélien Delogu 718 Sep 14, 2022
A request library that returns promises, inspired by request

then-request A request library that returns promises and supports both browsers and node.js Installation npm install then-request Usage request(metho

then (Promises/A+ implementations) 241 Nov 29, 2022
A polyfill for ES6-style Promises

ES6-Promise (subset of rsvp.js) This is a polyfill of the ES6 Promise. The implementation is a subset of rsvp.js extracted by @jakearchibald, if you'r

Stefan Penner 7.3k Dec 28, 2022