p-map vs bluebird
Promise and Concurrency Management Comparison
3 Years
p-mapbluebirdSimilar Packages:
What's Promise and Concurrency Management?

bluebird is a fully-featured Promise library that focuses on performance and provides advanced features like cancellation, progress reporting, and more. It is designed to be a drop-in replacement for native Promises, offering better performance and additional functionality. p-map, on the other hand, is a lightweight utility for mapping over asynchronous iterable data with a concurrency limit. It allows you to control how many promises are executed in parallel, making it ideal for scenarios where you want to limit resource usage while processing a collection of items asynchronously.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
p-map52,074,153
1,45021.2 kB129 months agoMIT
bluebird30,981,931
20,594-1236 years agoMIT
Feature Comparison: p-map vs bluebird

Concurrency Control

  • p-map:

    p-map is specifically designed for concurrency control. It allows you to set a limit on how many promises are executed in parallel, making it easy to manage resource usage and prevent overwhelming servers or APIs. This feature is built-in and straightforward to use.

  • bluebird:

    bluebird does not provide built-in concurrency control for promise execution. However, it offers features like Promise.map which can be combined with custom concurrency logic. You can implement your own concurrency control using Promise.map by limiting the number of concurrent promises manually.

Advanced Features

  • p-map:

    p-map is focused on a single task: mapping over iterables with concurrency control. It does not offer advanced features beyond this functionality, making it lightweight and easy to use for specific use cases but lacking the breadth of features found in bluebird.

  • bluebird:

    bluebird offers a rich set of advanced features including cancellation, progress reporting, and more. It provides a comprehensive API for handling complex asynchronous workflows, making it suitable for large-scale applications that require fine-grained control over promises.

Performance

  • p-map:

    p-map is lightweight and efficient, particularly when dealing with large arrays or iterables. Its performance is enhanced by the concurrency control feature, which prevents resource exhaustion by limiting the number of concurrent operations.

  • bluebird:

    bluebird is known for its high performance compared to native Promises, especially in scenarios involving a large number of promises. It is optimized for speed and memory usage, making it a reliable choice for performance-critical applications.

Ease of Use: Code Examples

  • p-map:

    p-map has a simple and straightforward API that is easy to understand and use. Its focus on a single task makes it easy to integrate into projects without a steep learning curve.

  • bluebird:

    bluebird provides a familiar Promise API with additional features that may require some learning to use effectively. Its documentation is comprehensive, and the library is designed to be intuitive for developers familiar with Promises.

Community and Ecosystem

  • p-map:

    p-map is a smaller library with a growing community. It is part of the p- family of promise utilities, which are well-regarded for their simplicity and effectiveness. However, it does not have the same level of ecosystem or third-party integrations as bluebird.

  • bluebird:

    bluebird has a large and active community, with extensive documentation and a wide range of plugins and integrations. It is a well-established library that is widely used in the JavaScript ecosystem.

Code Example

  • p-map:

    p-map Example

    const pMap = require('p-map');
    
    const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
    const tasks = [
      () => delay(1000).then(() => 'Task 1 completed'),
      () => delay(500).then(() => 'Task 2 completed'),
      () => delay(2000).then(() => 'Task 3 completed'),
      () => delay(1500).then(() => 'Task 4 completed'),
    ];
    
    // Using p-map with concurrency limit
    const concurrencyLimit = 2;
    pMap(tasks, task => task(), { concurrency: concurrencyLimit }).then(results => {
      console.log(results);
    });
    
  • bluebird:

    bluebird Example

    const Promise = require('bluebird');
    
    // Example of using bluebird for concurrency control
    const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
    const tasks = [
      () => delay(1000).then(() => console.log('Task 1 completed')),  
      () => delay(500).then(() => console.log('Task 2 completed')),  
      () => delay(2000).then(() => console.log('Task 3 completed')),  
      () => delay(1500).then(() => console.log('Task 4 completed')),
    ];
    
    // Custom concurrency control with bluebird
    const concurrencyLimit = 2;
    const executeWithLimit = (tasks, limit) => {
      const results = [];
      const executing = new Set();
    
      const enqueue = (task) => {
        const p = Promise.resolve().then(task);
        results.push(p);
        executing.add(p);
    
        p.finally(() => executing.delete(p));
    
        if (executing.size >= limit) {
          return Promise.race(executing).then(() => enqueue(task));
        }
        return enqueue(task);
      };
    
      tasks.forEach(enqueue);
      return Promise.all(results);
    };
    
    executeWithLimit(tasks, concurrencyLimit);
    
How to Choose: p-map vs bluebird
  • p-map:

    Choose p-map if you need a simple and efficient way to map over an array or iterable with a concurrency limit. It is ideal for tasks like processing API requests, file uploads, or any scenario where you want to limit the number of concurrent operations to avoid overwhelming resources.

  • bluebird:

    Choose bluebird if you need a comprehensive Promise library with advanced features like cancellation, progress reporting, and better performance compared to native Promises. It is suitable for complex asynchronous workflows where you need more control and functionality.

README for p-map

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('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.

pMapIterable(input, mapper, options?)

Returns an async iterable that streams each return value from mapper in order.

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);
};

input

Type: AsyncIterable<Promise<unknown> | unknown> | Iterable<Promise<unknown> | unknown>

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.

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.

backpressure

Only for pMapIterable

Type: number (Integer)
Default: options.concurrency
Minimum: options.concurrency

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.

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.

stopOnError

Only for pMap

Type: boolean
Default: true

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 containing all the errors from the rejected promises.

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 can be implemented for abort control.

signal

Only for pMap

Type: AbortSignal

You can abort the promises using AbortController.

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.

pMapSkip

Return this value from a mapper function to skip including the value in the returned 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/']

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
  • More…