p-limit vs async vs bluebird vs promise-limit vs promise-queue
JavaScript Promise and Async Control Libraries
p-limitasyncbluebirdpromise-limitpromise-queueSimilar Packages:
JavaScript Promise and Async Control Libraries

JavaScript Promise and Async Control Libraries are tools that help manage asynchronous operations in JavaScript, providing more control over how and when these operations are executed. They offer features like limiting concurrency, queuing tasks, and handling promises more efficiently, which can improve performance and resource management in applications. These libraries are particularly useful in scenarios where you need to perform multiple asynchronous tasks but want to avoid overwhelming the system or running into issues like callback hell or unhandled promise rejections. They provide a more structured and manageable way to work with asynchronous code, making it easier to write, read, and maintain.

Npm Package Weekly Downloads Trend
3 Years
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
p-limit180,627,2712,70211.7 kB52 months agoMIT
async73,829,58528,218808 kB22a year agoMIT
bluebird35,363,20920,769-1276 years agoMIT
promise-limit1,094,323143-107 years agoISC
promise-queue962,603230-108 years agoMIT
Feature Comparison: p-limit vs async vs bluebird vs promise-limit vs promise-queue

Concurrency Control

  • p-limit:

    p-limit is specifically designed for limiting the concurrency of promise-based tasks. You can create a limit function that enforces a maximum number of concurrent promises, making it simple to control resource usage.

  • async:

    The async library provides various functions for controlling concurrency, such as async.parallelLimit and async.eachLimit, allowing you to specify limits on how many tasks run simultaneously.

  • bluebird:

    bluebird offers concurrency control through its Promise.map method, which allows you to set a concurrency limit while mapping over an array of values, executing promises in parallel up to the specified limit.

  • promise-limit:

    promise-limit provides a straightforward way to limit the number of concurrent promises. It exports a function that takes a limit and returns a wrapper function to control concurrency when executing promises.

  • promise-queue:

    promise-queue manages concurrency by queuing tasks and executing them in order with a specified limit on how many run simultaneously. This ensures that tasks are completed in the order they were added.

Task Queuing

  • p-limit:

    p-limit does not provide task queuing features. It focuses solely on limiting concurrency for promise-based tasks without managing their execution order.

  • async:

    async supports task queuing through its queue and priorityQueue functions, allowing you to create queues with customizable concurrency and priority levels.

  • bluebird:

    bluebird does not have built-in task queuing, but you can implement it using its promise chaining and mapping features. The library focuses more on promise management than queuing.

  • promise-limit:

    promise-limit does not include task queuing capabilities. It is designed for simple concurrency limiting without queuing tasks for later execution.

  • promise-queue:

    promise-queue is designed for task queuing, ensuring that tasks are executed in the order they are added to the queue. It allows you to set a concurrency limit while maintaining the order of execution.

Error Handling

  • p-limit:

    p-limit handles errors in promise-based tasks by allowing them to be rejected as usual. It does not provide special error handling features but works seamlessly with standard promise error handling.

  • async:

    async provides robust error handling mechanisms, including support for error-first callbacks, try/catch in async functions, and the ability to handle errors in parallel and series tasks.

  • bluebird:

    bluebird offers advanced error handling features, including promise cancellation, error propagation, and the ability to catch errors at different stages of promise execution. It also supports unhandled rejection tracking.

  • promise-limit:

    promise-limit allows errors to be handled by the promises it manages. It does not introduce any special error handling mechanisms, relying on standard promise behavior.

  • promise-queue:

    promise-queue handles errors by allowing rejected promises to propagate through the queue. It does not provide specialized error handling but ensures that errors are managed in the order tasks are executed.

Performance

  • p-limit:

    p-limit is lightweight and introduces minimal overhead when limiting concurrency. It is designed for performance, making it suitable for scenarios where you need to control concurrency without significant impact on execution speed.

  • async:

    async is efficient for managing asynchronous operations, but its performance can vary depending on the complexity of the tasks and the concurrency settings. It is designed for flexibility rather than raw performance.

  • bluebird:

    bluebird is one of the fastest promise libraries available, optimized for performance with features like lazy evaluation, efficient memory usage, and minimal overhead for promise creation and resolution.

  • promise-limit:

    promise-limit is designed to be simple and efficient, with low overhead for limiting concurrent promise execution. It is suitable for performance-sensitive applications that require basic concurrency control.

  • promise-queue:

    promise-queue is efficient in managing queued tasks, but its performance depends on the concurrency limit and the number of tasks. It is designed to balance order and concurrency without significant overhead.

Ease of Use: Code Examples

  • p-limit:

    Concurrency control with p-limit library

    const pLimit = require('p-limit');
    
    const limit = pLimit(2); // Limit concurrency to 2
    const tasks = [
      () => new Promise((resolve) => setTimeout(() => resolve('Task 1 complete'), 1000)),
      () => new Promise((resolve) => setTimeout(() => resolve('Task 2 complete'), 500)),
      () => new Promise((resolve) => setTimeout(() => resolve('Task 3 complete'), 2000)),
    ];
    
    const limitedTasks = tasks.map((task) => limit(task));
    Promise.all(limitedTasks)
      .then((results) => console.log(results))
      .catch((err) => console.error(err));
    
  • async:

    Concurrency control with async library

    const async = require('async');
    
    const tasks = [
      (callback) => setTimeout(() => callback(null, 'Task 1 complete'), 1000),
      (callback) => setTimeout(() => callback(null, 'Task 2 complete'), 500),
      (callback) => setTimeout(() => callback(null, 'Task 3 complete'), 2000),
    ];
    
    // Limit concurrency to 2 tasks at a time
    async.parallelLimit(tasks, 2, (err, results) => {
      if (err) console.error(err);
      console.log(results);
    });
    
  • bluebird:

    Concurrency control with bluebird library

    const Promise = require('bluebird');
    
    const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
    const tasks = [
      () => delay(1000).then(() => 'Task 1 complete'),
      () => delay(500).then(() => 'Task 2 complete'),
      () => delay(2000).then(() => 'Task 3 complete'),
    ];
    
    // Limit concurrency to 2 tasks at a time
    Promise.map(tasks, (task) => task(), { concurrency: 2 })
      .then((results) => console.log(results))
      .catch((err) => console.error(err));
    
  • promise-limit:

    Concurrency control with promise-limit library

    const promiseLimit = require('promise-limit');
    
    const limit = promiseLimit(2); // Limit concurrency to 2
    const tasks = [
      () => new Promise((resolve) => setTimeout(() => resolve('Task 1 complete'), 1000)),
      () => new Promise((resolve) => setTimeout(() => resolve('Task 2 complete'), 500)),
      () => new Promise((resolve) => setTimeout(() => resolve('Task 3 complete'), 2000)),
    ];
    
    const limitedTasks = tasks.map((task) => limit(task));
    Promise.all(limitedTasks)
      .then((results) => console.log(results))
      .catch((err) => console.error(err));
    
  • promise-queue:

    Task queuing with promise-queue library

    const PromiseQueue = require('promise-queue');
    
    const queue = new PromiseQueue(2, Infinity); // Limit concurrency to 2
    const tasks = [
      () => new Promise((resolve) => setTimeout(() => resolve('Task 1 complete'), 1000)),
      () => new Promise((resolve) => setTimeout(() => resolve('Task 2 complete'), 500)),
      () => new Promise((resolve) => setTimeout(() => resolve('Task 3 complete'), 2000)),
    ];
    
    // Add tasks to the queue
    const promises = tasks.map((task) => queue.add(task));
    Promise.all(promises)
      .then((results) => console.log(results))
      .catch((err) => console.error(err));
    
How to Choose: p-limit vs async vs bluebird vs promise-limit vs promise-queue
  • p-limit:

    Choose p-limit if you need a simple and lightweight solution for limiting the concurrency of promise-based tasks. It is perfect for scenarios where you want to control the number of promises running simultaneously without adding much overhead.

  • async:

    Choose async if you need a comprehensive toolkit for managing asynchronous operations with a wide range of utilities, including parallel, series, and waterfall execution. It is ideal for complex workflows that require fine-grained control over task execution.

  • bluebird:

    Choose bluebird if you want a high-performance promise library that offers advanced features like cancellation, progress tracking, and a rich set of utility methods. It is suitable for applications that require efficient promise handling and want to avoid the limitations of native promises.

  • promise-limit:

    Choose promise-limit if you want a straightforward implementation for limiting the number of concurrent promises. It is easy to use and integrates well with existing promise-based code, making it a good choice for projects that need basic concurrency control.

  • promise-queue:

    Choose promise-queue if you need a queue-based approach to managing asynchronous tasks, ensuring that they are executed in order and with a specified concurrency limit. It is ideal for scenarios where task order is important, and you want to prevent resource exhaustion.

README for p-limit

p-limit

Run multiple promise-returning & async functions with limited concurrency

Works in Node.js and browsers.

Install

npm install p-limit

Usage

import pLimit from 'p-limit';

const limit = pLimit(1);

const input = [
	limit(() => fetchSomething('foo')),
	limit(() => fetchSomething('bar')),
	limit(() => doSomething())
];

// Only one promise is run at once
const result = await Promise.all(input);
console.log(result);

API

pLimit(concurrency) default export

Returns a limit function.

concurrency

Type: number
Minimum: 1

Concurrency limit.

limit(fn, ...args)

Returns the promise returned by calling fn(...args).

fn

Type: Function

Promise-returning/async function.

args

Any arguments to pass through to fn.

Support for passing arguments on to the fn is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a lot of functions.

limit.map(iterable, mapperFunction)

Process an iterable of inputs with limited concurrency.

The mapper function receives the item value and its index.

Returns a promise equivalent to Promise.all(Array.from(iterable, (item, index) => limit(mapperFunction, item, index))).

This is a convenience function for processing inputs that arrive in batches. For more complex use cases, see p-map.

limit.activeCount

The number of promises that are currently running.

limit.pendingCount

The number of promises that are waiting to run (i.e. their internal fn was not called yet).

limit.clearQueue()

Discard pending promises that are waiting to run.

This might be useful if you want to teardown the queue at the end of your program's lifecycle or discard any function calls referencing an intermediary state of your app.

Note: This does not cancel promises that are already running.

limit.concurrency

Get or set the concurrency limit.

limitFunction(fn, options) named export

Returns a function with limited concurrency.

The returned function manages its own concurrent executions, allowing you to call it multiple times without exceeding the specified concurrency limit.

Ideal for scenarios where you need to control the number of simultaneous executions of a single function, rather than managing concurrency across multiple functions.

import {limitFunction} from 'p-limit';

const limitedFunction = limitFunction(async () => {
	return doSomething();
}, {concurrency: 1});

const input = Array.from({length: 10}, limitedFunction);

// Only one promise is run at once.
await Promise.all(input);

fn

Type: Function

Promise-returning/async function.

options

Type: object

concurrency

Type: number
Minimum: 1

Concurrency limit.

FAQ

How is this different from the p-queue package?

This package is only about limiting the number of concurrent executions, while p-queue is a fully featured queue implementation with lots of different options, introspection, and ability to pause the queue.

Related

  • p-throttle - Throttle promise-returning & async functions
  • p-debounce - Debounce promise-returning & async functions
  • p-map - Run promise-returning & async functions concurrently with different inputs
  • p-all - Run promise-returning & async functions concurrently with optional limited concurrency
  • More…