![Async Logo](https://raw.githubusercontent.com/caolan/async/master/logo/async-logo_readme.jpg)
[![Build Status via Travis CI](https://travis-ci.org/caolan/async.svg?branch=master)](https://travis-ci.org/caolan/async)
[![NPM version](https://img.shields.io/npm/v/async.svg)](https://www.npmjs.com/package/async)
[![Coverage Status](https://coveralls.io/repos/caolan/async/badge.svg?branch=master)](https://coveralls.io/r/caolan/async?branch=master)
[![Join the chat at https://gitter.im/caolan/async](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/caolan/async?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
*For Async v1.5.x documentation, go [HERE](https://github.com/caolan/async/blob/v1.5.2/README.md)*
Async is a utility module which provides straight-forward, powerful functions
for working with asynchronous JavaScript. Although originally designed for
use with [Node.js](https://nodejs.org/) and installable via `npm i async`,
it can also be used directly in the browser.
Async is also installable via:
- [yarn](https://yarnpkg.com/en/): `yarn add async`
Async provides around 70 functions that include the usual 'functional'
suspects (`map`, `reduce`, `filter`, `each`…) as well as some common patterns
for asynchronous control flow (`parallel`, `series`, `waterfall`…). All these
functions assume you follow the Node.js convention of providing a single
callback as the last argument of your asynchronous function -- a callback which expects an Error as its first argument -- and calling the callback once.
You can also pass `async` functions to Async methods, instead of callback-accepting functions. For more information, see [AsyncFunction](global.html#AsyncFunction)
## Quick Examples
```js
async.map(['file1','file2','file3'], fs.stat, function(err, results) {
// results is now an array of stats for each file
});
async.filter(['file1','file2','file3'], function(filePath, callback) {
fs.access(filePath, function(err) {
callback(null, !err)
});
}, function(err, results) {
// results now equals an array of the existing files
});
async.parallel([
function(callback) { ... },
function(callback) { ... }
], function(err, results) {
// optional callback
});
async.series([
function(callback) { ... },
function(callback) { ... }
]);
```
There are many more functions available so take a look at the docs below for a
full list. This module aims to be comprehensive, so if you feel anything is
missing please create a GitHub issue for it.
## Common Pitfalls [(StackOverflow)](http://stackoverflow.com/questions/tagged/async.js)
### Synchronous iteration functions
If you get an error like `RangeError: Maximum call stack size exceeded.` or other stack overflow issues when using async, you are likely using a synchronous iteratee. By *synchronous* we mean a function that calls its callback on the same tick in the javascript event loop, without doing any I/O or using any timers. Calling many callbacks iteratively will quickly overflow the stack. If you run into this issue, just defer your callback with `async.setImmediate` to start a new call stack on the next tick of the event loop.
This can also arise by accident if you callback early in certain cases:
```js
async.eachSeries(hugeArray, function iteratee(item, callback) {
if (inCache(item)) {
callback(null, cache[item]); // if many items are cached, you'll overflow
} else {
doSomeIO(item, callback);
}
}, function done() {
//...
});
```
Just change it to:
```js
async.eachSeries(hugeArray, function iteratee(item, callback) {
if (inCache(item)) {
async.setImmediate(function() {
callback(null, cache[item]);
});
} else {
doSomeIO(item, callback);
//...
}
});
```
Async does not guard against synchronous iteratees for performance reasons. If you are still running into stack overflows, you can defer as suggested above, or wrap functions with [`async.ensureAsync`](#ensureAsync) Functions that are asynchronous by their nature do not have this problem and don't need the extra callback deferral.
If JavaScript's event loop is still a bit nebulous, check out [this article](http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/) or [this talk](http://2014.jsconf.eu/speakers/philip-roberts-what-the-heck-is-the-event-loop-anyway.html) for more detailed information about how it works.
### Multiple callbacks
Make sure to always `return` when calling a callback early, otherwise you will cause multiple callbacks and unpredictable behavior in many cases.
```js
async.waterfall([
function(callback) {
getSomething(options, function (err, result) {
if (err) {
callback(new Error("failed getting something:" + err.message));
// we should return here
}
// since we did not return, this callback still will be called and
// `processData` will be called twice
callback(null, result);
});
},
processData
], done)
```
It is always good practice to `return callback(err, result)` whenever a callback call is not the last statement of a function.
### Using ES2017 `async` functions
Async accepts `async` functions wherever we accept a Node-style callback function. However, we do not pass them a callback, and instead use the return value and handle any promise rejections or errors thrown.
```js
async.mapLimit(files, 10, async file => { // <- no callback!
const text = await util.promisify(fs.readFile)(dir + file, 'utf8')
const body = JSON.parse(text) // <- a parse error here will be caught automatically
if (!(await checkValidity(body))) {
throw new Error(`${file} has invalid contents`) // <- this error will also be caught
}
return body // <- return a value!
}, (err, contents) => {
if (err) throw err
console.log(contents)
})
```
We can only detect native `async` functions, not transpiled versions (e.g. with Babel). Otherwise, you can wrap `async` functions in `async.asyncify()`.
### Binding a context to an iteratee
This section is really about `bind`, not about Async. If you are wondering how to
make Async execute your iteratees in a given context, or are confused as to why
a method of another library isn't working as an iteratee, study this example:
```js
// Here is a simple object with an (unnecessarily roundabout) squaring method
var AsyncSquaringLibrary = {
squareExponent: 2,
square: function(number, callback){
var result = Math.pow(number, this.squareExponent);
setTimeout(function(){
callback(null, result);
}, 200);
}
};
async.map([1, 2, 3], AsyncSquaringLibrary.square, function(err, result) {
// result is [NaN, NaN, NaN]
// This fails because the `this.squareExponent` expression in the square
// function is not evaluated in the context of AsyncSquaringLibrary, and is
// therefore undefined.
});
async.map([1, 2, 3], AsyncSquaringLibrary.square.bind(AsyncSquaringLibrary), function(err, result) {
// result is [1, 4, 9]
// With the help of bind we can attach a context to the iteratee before
// passing it to Async. Now the square function will be executed in its
// 'home' AsyncSquaringLibrary context and the value of `this.squareExponent`
// will be as expected.
});
```
### Subtle Memory Leaks
There are cases where you might want to exit early from async flow, when calling an Async method inside another async function:
```javascript
function myFunction (args, outerCallback) {
async.waterfall([
//...
function (arg, next) {
if (someImportantCondition()) {
return outerCallback(null)
}
},
function (arg, next) {/*...*/}
], function done (err) {
//...
})
}
```
Something happened in a waterfall where you want to skip the rest of the execution, so you call an outer callack. However, Async will still wait for that inner `next` callback to be called, leaving some closure scope allocated.
As of version 3.0, you can call any Async callback with `false` as the `error` argument, and the rest of the execution of the Async method will be stopped or ignored.
```javascript
function (arg, next) {
if (someImportantCondition()) {
outerCallback(null)
return next(false) // ← signal that you called an outer callback
}
},
```
### Mutating collections while processing them
If you pass an array to a collection method (such as `each`, `mapLimit`, or `filterSeries`), and then attempt to `push`, `pop`, or `splice` additional items on to the array, this could lead to unexpected or undefined behavior. Async will iterate until the original `length` of the array is met, and the indexes of items `pop()`ed or `splice()`d could already have been processed. Therefore, it is not recommended to modify the array after Async has begun iterating over it. If you do need to `push`, `pop`, or `splice`, use a `queue` instead.
## Download
The source is available for download from
[GitHub](https://raw.githubusercontent.com/caolan/async/master/dist/async.min.js).
Alternatively, you can install using npm:
```bash
$ npm i async
```
You can then `require()` async as normal:
```js
var async = require("async");
```
Or require individual methods:
```js
var waterfall = require("async/waterfall");
var map = require("async/map");
```
__Development:__ [async.js](https://raw.githubusercontent.com/caolan/async/master/dist/async.js) - 29.6kb Uncompressed
### In the Browser
Async should work in any ES2015 environment (Node 6+ and all modern browsers).
If you want to use Async in an older environment, (e.g. Node 4, IE11) you will have to transpile.
Usage:
```html
```
The portable versions of Async, including `async.js` and `async.min.js`, are
included in the `/dist` folder. Async can also be found on the [jsDelivr CDN](http://www.jsdelivr.com/projects/async).
### ES Modules
Async includes a `.mjs` version that should automatically be used by compatible bundlers such as Webpack or Rollup, anything that uses the `module` field of the `package.json`.
We also provide Async as a collection of purely ES2015 modules, in an alternative `async-es` package on npm.
```bash
$ npm install async-es
```
```js
import waterfall from 'async-es/waterfall';
import async from 'async-es';
```
### Typescript
There are third-party type definitions for Async.
```
npm i -D @types/async
```
It is recommended to target ES2017 or higher in your `tsconfig.json`, so `async` functions are preserved:
```json
{
"compilerOptions": {
"target": "es2017"
}
}
```
## Other Libraries
* [`limiter`](https://www.npmjs.com/package/limiter) a package for rate-limiting based on requests per sec/hour.
* [`neo-async`](https://www.npmjs.com/package/neo-async) an altername implementation of Async, focusing on speed.
* [`co-async`](https://www.npmjs.com/package/co-async) a library inspired by Async for use with [`co`](https://www.npmjs.com/package/co) and generator functions.
* [`promise-async`](https://www.npmjs.com/package/promise-async) a version of Async where all the methods are Promisified.
* ['modern-async'](https://www.npmjs.com/package/modern-async) an alternative to Async using only async/await and promises.