p-map vs bluebird vs async vs q
JavaScript Promise Libraries
p-mapbluebirdasyncqSimilar Packages:

JavaScript Promise Libraries

JavaScript Promise libraries are essential tools for handling asynchronous operations in a more manageable and readable way. They provide various utilities to work with promises, enabling developers to write cleaner code while avoiding callback hell. These libraries enhance the native Promise API, offering additional features such as concurrency control, error handling, and improved performance. By leveraging these libraries, developers can streamline their asynchronous workflows, making it easier to compose and manage complex asynchronous tasks in their applications.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
p-map72,083,7211,48221.3 kB114 months agoMIT
bluebird43,243,55020,757-1276 years agoMIT
async028,194808 kB242 years agoMIT
q015,227-115-MIT

Feature Comparison: p-map vs bluebird vs async vs q

Concurrency Control

  • p-map:

    P-map is specifically designed for concurrency control, allowing you to set a limit on how many promises are executed concurrently. This feature is essential for managing resources effectively when dealing with multiple asynchronous operations.

  • bluebird:

    Bluebird offers built-in support for concurrency control through methods like Promise.map with a concurrency option, allowing you to specify how many promises to run in parallel, which is particularly useful for resource-intensive tasks.

  • async:

    Async provides various functions that allow you to control the concurrency of asynchronous operations, such as async.parallelLimit and async.eachLimit, making it easy to manage how many tasks run simultaneously.

  • q:

    Q does not provide built-in concurrency control features, focusing instead on basic promise functionality. For concurrency control, additional logic would need to be implemented manually.

Error Handling

  • p-map:

    P-map allows you to handle errors in the mapping function, and if an error occurs, it will reject the promise, making it easier to manage errors in a concurrent mapping scenario.

  • bluebird:

    Bluebird enhances error handling with its promise chaining capabilities, allowing you to catch errors at any point in the promise chain using .catch(). It also supports Promise.try for wrapping synchronous code in a promise, making error handling more straightforward.

  • async:

    Async provides robust error handling capabilities through its callback-based approach, allowing you to handle errors at each step of the asynchronous flow, which can be particularly useful in complex workflows.

  • q:

    Q provides basic error handling through promise rejection, allowing you to catch errors using .catch(), but lacks the advanced error handling features found in other libraries.

Performance

  • p-map:

    P-map is lightweight and designed for performance when mapping over asynchronous operations, ensuring that it does not introduce significant overhead while managing concurrency.

  • bluebird:

    Bluebird is known for its high performance, particularly in promise-heavy applications. It is optimized for speed and can outperform native promises in many scenarios due to its efficient implementation.

  • async:

    Async is optimized for performance in managing asynchronous control flows, but its callback-based nature may introduce some overhead compared to promise-based libraries.

  • q:

    Q is relatively simple and performs adequately for basic promise functionality, but it may not match the performance optimizations found in more feature-rich libraries like Bluebird.

Learning Curve

  • p-map:

    P-map has a low learning curve, especially for developers familiar with the native Promise API, as it provides a straightforward method for mapping over asynchronous tasks.

  • bluebird:

    Bluebird has a relatively gentle learning curve for those already familiar with promises, as it extends the native Promise API with additional features that are easy to grasp.

  • async:

    Async has a moderate learning curve due to its callback-based API, which may require developers to familiarize themselves with its various functions and control flow patterns.

  • q:

    Q is easy to learn for beginners, as it offers a simple and intuitive API for working with promises, making it a good choice for those new to asynchronous programming.

Extensibility

  • p-map:

    P-map is focused on a specific use case (mapping with concurrency) and is not designed for extensibility beyond that, making it less flexible than the other libraries.

  • bluebird:

    Bluebird is also extensible, providing a range of utility methods that can be combined to create powerful asynchronous workflows, and it supports promisifying existing APIs easily.

  • async:

    Async is highly extensible, allowing developers to create custom control flow functions and integrate them into their workflows, making it suitable for complex applications.

  • q:

    Q is less extensible compared to others, as it primarily focuses on basic promise functionality without offering extensive utility methods or customization options.

How to Choose: p-map vs bluebird vs async vs q

  • p-map:

    Choose p-map if you need a lightweight library specifically designed for mapping over asynchronous operations with concurrency control. It allows you to limit the number of concurrent promises, making it ideal for scenarios where you want to avoid overwhelming resources while processing multiple asynchronous tasks.

  • bluebird:

    Choose Bluebird if you require a high-performance promise library with extensive features such as cancellation, progress tracking, and a variety of utility methods for working with promises. Bluebird is optimized for speed and can significantly improve performance in promise-heavy applications.

  • async:

    Choose Async if you need a versatile library that provides a rich set of functions for working with asynchronous JavaScript, including control flow functions like series, parallel, and waterfall. It is particularly useful for managing multiple asynchronous operations and offers a straightforward API for handling callbacks.

  • q:

    Choose Q if you are looking for a simple and easy-to-use promise library that provides a clean API for working with promises. It is particularly useful for projects that require basic promise functionality without the overhead of additional features.

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…