p-map vs bluebird vs q vs async
JavaScript 异步控制库
p-mapbluebirdqasync类似的npm包:

JavaScript 异步控制库

JavaScript 异步控制库是用于处理异步操作的工具,它们提供了多种方法来简化异步编程,尤其是在处理回调地狱和复杂的异步流程时。这些库通过提供更清晰的语法和结构,使得开发者能够更容易地管理并发操作、错误处理和结果组合。选择合适的异步控制库可以显著提高代码的可读性和可维护性。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
p-map72,083,7211,48221.3 kB114 个月前MIT
bluebird43,243,55020,757-1276 年前MIT
q14,175,38015,227-115-MIT
async028,194808 kB242 年前MIT

功能对比: p-map vs bluebird vs q vs async

异步控制

  • p-map:

    p-map 专注于对数组进行异步映射,允许开发者限制并发执行的数量,适合处理大量异步任务时的性能优化。

  • bluebird:

    bluebird 通过 Promise 的方式处理异步操作,支持链式调用和并行处理,提供了丰富的 API 来简化异步编程。

  • q:

    q 提供了基本的 Promise 功能,允许开发者使用 Promise 的方式处理异步操作,适合简单的异步需求。

  • async:

    async 提供了一系列控制流函数,如 series, parallel, waterfall 等,允许开发者以不同的方式组织异步操作,避免回调地狱。

错误处理

  • p-map:

    p-map 允许在映射过程中处理错误,可以通过 Promise 的方式捕获错误,简化错误处理流程。

  • bluebird:

    bluebird 提供了强大的错误处理机制,支持 .catch().finally() 方法,能够更优雅地捕获和处理错误。

  • q:

    q 提供了基本的错误处理机制,支持 .catch() 方法,但功能相对简单。

  • async:

    async 通过回调函数的方式处理错误,开发者需要在每个回调中检查错误,可能会导致错误处理不一致。

性能

  • p-map:

    p-map 通过限制并发数量来优化性能,适合处理大量异步任务时的性能管理。

  • bluebird:

    bluebird 以高性能著称,特别是在处理大量并发 Promise 时,能够有效减少内存占用和提升执行速度。

  • q:

    q 的性能相对较低,适合简单的异步需求,不适合高并发场景。

  • async:

    async 的性能依赖于回调的实现,可能在复杂场景下导致性能下降,尤其是在大量异步操作时。

学习曲线

  • p-map:

    p-map 的学习曲线较为简单,API 直观易懂,适合快速上手。

  • bluebird:

    bluebird 的学习曲线稍陡,尤其是其丰富的 API 和功能,但一旦掌握,可以显著提高异步编程的效率。

  • q:

    q 的学习曲线非常平缓,适合对 Promise 不太熟悉的开发者,易于理解和使用。

  • async:

    async 的学习曲线相对较平缓,开发者可以快速上手,但在复杂场景下可能需要深入理解其控制流机制。

社区支持

  • p-map:

    p-map 的社区相对较小,但文档清晰,适合快速上手。

  • bluebird:

    bluebird 也有强大的社区支持,提供了丰富的文档和示例,适合需要深入使用的开发者。

  • q:

    q 的社区支持较少,适合简单的异步需求,但在复杂场景下可能缺乏支持。

  • async:

    async 拥有广泛的社区支持和文档,适合初学者和中级开发者使用。

如何选择: p-map vs bluebird vs q vs async

  • p-map:

    选择 p-map 如果你需要对数组中的每个元素进行异步操作,并希望限制并发数量。它提供了简单的 API,适合处理大量异步任务时需要控制并发的情况。

  • bluebird:

    选择 bluebird 如果你需要一个功能强大的 Promise 库,提供丰富的功能(如并行处理、错误处理、性能优化等),并且希望利用其高效的性能和丰富的 API。它适合需要复杂异步操作的场景。

  • q:

    选择 q 如果你需要一个轻量级的 Promise 库,并且希望使用类似于传统回调的方式来处理异步操作。它适合那些对 Promise 语法不太熟悉的开发者。

  • async:

    选择 async 如果你需要一个简单的控制流库,支持多种异步模式(如并行、串行、限制并发等),并且希望与 Node.js 的回调风格兼容。它非常适合处理简单的异步任务。

p-map的README

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…