|
|
@@ -0,0 +1,1647 @@
|
|
|
+# Async.js
|
|
|
+
|
|
|
+[](https://travis-ci.org/caolan/async)
|
|
|
+
|
|
|
+
|
|
|
+Async is a utility module which provides straight-forward, powerful functions
|
|
|
+for working with asynchronous JavaScript. Although originally designed for
|
|
|
+use with [Node.js](http://nodejs.org) and installable via `npm install async`,
|
|
|
+it can also be used directly in the browser.
|
|
|
+
|
|
|
+Async is also installable via:
|
|
|
+
|
|
|
+- [bower](http://bower.io/): `bower install async`
|
|
|
+- [component](https://github.com/component/component): `component install
|
|
|
+ caolan/async`
|
|
|
+- [jam](http://jamjs.org/): `jam install async`
|
|
|
+- [spm](http://spmjs.io/): `spm install async`
|
|
|
+
|
|
|
+Async provides around 20 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 `async` function.
|
|
|
+
|
|
|
+
|
|
|
+## Quick Examples
|
|
|
+
|
|
|
+```javascript
|
|
|
+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'], fs.exists, function(results){
|
|
|
+ // results now equals an array of the existing files
|
|
|
+});
|
|
|
+
|
|
|
+async.parallel([
|
|
|
+ function(){ ... },
|
|
|
+ function(){ ... }
|
|
|
+], callback);
|
|
|
+
|
|
|
+async.series([
|
|
|
+ function(){ ... },
|
|
|
+ function(){ ... }
|
|
|
+]);
|
|
|
+```
|
|
|
+
|
|
|
+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
|
|
|
+
|
|
|
+### Binding a context to an iterator
|
|
|
+
|
|
|
+This section is really about `bind`, not about `async`. If you are wondering how to
|
|
|
+make `async` execute your iterators in a given context, or are confused as to why
|
|
|
+a method of another library isn't working as an iterator, 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 iterator 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.
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+## Download
|
|
|
+
|
|
|
+The source is available for download from
|
|
|
+[GitHub](http://github.com/caolan/async).
|
|
|
+Alternatively, you can install using Node Package Manager (`npm`):
|
|
|
+
|
|
|
+ npm install async
|
|
|
+
|
|
|
+__Development:__ [async.js](https://github.com/caolan/async/raw/master/lib/async.js) - 29.6kb Uncompressed
|
|
|
+
|
|
|
+## In the Browser
|
|
|
+
|
|
|
+So far it's been tested in IE6, IE7, IE8, FF3.6 and Chrome 5.
|
|
|
+
|
|
|
+Usage:
|
|
|
+
|
|
|
+```html
|
|
|
+<script type="text/javascript" src="async.js"></script>
|
|
|
+<script type="text/javascript">
|
|
|
+
|
|
|
+ async.map(data, asyncProcess, function(err, results){
|
|
|
+ alert(results);
|
|
|
+ });
|
|
|
+
|
|
|
+</script>
|
|
|
+```
|
|
|
+
|
|
|
+## Documentation
|
|
|
+
|
|
|
+### Collections
|
|
|
+
|
|
|
+* [`each`](#each)
|
|
|
+* [`eachSeries`](#eachSeries)
|
|
|
+* [`eachLimit`](#eachLimit)
|
|
|
+* [`map`](#map)
|
|
|
+* [`mapSeries`](#mapSeries)
|
|
|
+* [`mapLimit`](#mapLimit)
|
|
|
+* [`filter`](#filter)
|
|
|
+* [`filterSeries`](#filterSeries)
|
|
|
+* [`reject`](#reject)
|
|
|
+* [`rejectSeries`](#rejectSeries)
|
|
|
+* [`reduce`](#reduce)
|
|
|
+* [`reduceRight`](#reduceRight)
|
|
|
+* [`detect`](#detect)
|
|
|
+* [`detectSeries`](#detectSeries)
|
|
|
+* [`sortBy`](#sortBy)
|
|
|
+* [`some`](#some)
|
|
|
+* [`every`](#every)
|
|
|
+* [`concat`](#concat)
|
|
|
+* [`concatSeries`](#concatSeries)
|
|
|
+
|
|
|
+### Control Flow
|
|
|
+
|
|
|
+* [`series`](#seriestasks-callback)
|
|
|
+* [`parallel`](#parallel)
|
|
|
+* [`parallelLimit`](#parallellimittasks-limit-callback)
|
|
|
+* [`whilst`](#whilst)
|
|
|
+* [`doWhilst`](#doWhilst)
|
|
|
+* [`until`](#until)
|
|
|
+* [`doUntil`](#doUntil)
|
|
|
+* [`forever`](#forever)
|
|
|
+* [`waterfall`](#waterfall)
|
|
|
+* [`compose`](#compose)
|
|
|
+* [`seq`](#seq)
|
|
|
+* [`applyEach`](#applyEach)
|
|
|
+* [`applyEachSeries`](#applyEachSeries)
|
|
|
+* [`queue`](#queue)
|
|
|
+* [`priorityQueue`](#priorityQueue)
|
|
|
+* [`cargo`](#cargo)
|
|
|
+* [`auto`](#auto)
|
|
|
+* [`retry`](#retry)
|
|
|
+* [`iterator`](#iterator)
|
|
|
+* [`apply`](#apply)
|
|
|
+* [`nextTick`](#nextTick)
|
|
|
+* [`times`](#times)
|
|
|
+* [`timesSeries`](#timesSeries)
|
|
|
+
|
|
|
+### Utils
|
|
|
+
|
|
|
+* [`memoize`](#memoize)
|
|
|
+* [`unmemoize`](#unmemoize)
|
|
|
+* [`log`](#log)
|
|
|
+* [`dir`](#dir)
|
|
|
+* [`noConflict`](#noConflict)
|
|
|
+
|
|
|
+
|
|
|
+## Collections
|
|
|
+
|
|
|
+<a name="forEach" />
|
|
|
+<a name="each" />
|
|
|
+### each(arr, iterator, callback)
|
|
|
+
|
|
|
+Applies the function `iterator` to each item in `arr`, in parallel.
|
|
|
+The `iterator` is called with an item from the list, and a callback for when it
|
|
|
+has finished. If the `iterator` passes an error to its `callback`, the main
|
|
|
+`callback` (for the `each` function) is immediately called with the error.
|
|
|
+
|
|
|
+Note, that since this function applies `iterator` to each item in parallel,
|
|
|
+there is no guarantee that the iterator functions will complete in order.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `arr` - An array to iterate over.
|
|
|
+* `iterator(item, callback)` - A function to apply to each item in `arr`.
|
|
|
+ The iterator is passed a `callback(err)` which must be called once it has
|
|
|
+ completed. If no error has occurred, the `callback` should be run without
|
|
|
+ arguments or with an explicit `null` argument.
|
|
|
+* `callback(err)` - A callback which is called when all `iterator` functions
|
|
|
+ have finished, or an error occurs.
|
|
|
+
|
|
|
+__Examples__
|
|
|
+
|
|
|
+
|
|
|
+```js
|
|
|
+// assuming openFiles is an array of file names and saveFile is a function
|
|
|
+// to save the modified contents of that file:
|
|
|
+
|
|
|
+async.each(openFiles, saveFile, function(err){
|
|
|
+ // if any of the saves produced an error, err would equal that error
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+```js
|
|
|
+// assuming openFiles is an array of file names
|
|
|
+
|
|
|
+async.each(openFiles, function(file, callback) {
|
|
|
+
|
|
|
+ // Perform operation on file here.
|
|
|
+ console.log('Processing file ' + file);
|
|
|
+
|
|
|
+ if( file.length > 32 ) {
|
|
|
+ console.log('This file name is too long');
|
|
|
+ callback('File name too long');
|
|
|
+ } else {
|
|
|
+ // Do work to process file here
|
|
|
+ console.log('File processed');
|
|
|
+ callback();
|
|
|
+ }
|
|
|
+}, function(err){
|
|
|
+ // if any of the file processing produced an error, err would equal that error
|
|
|
+ if( err ) {
|
|
|
+ // One of the iterations produced an error.
|
|
|
+ // All processing will now stop.
|
|
|
+ console.log('A file failed to process');
|
|
|
+ } else {
|
|
|
+ console.log('All files have been processed successfully');
|
|
|
+ }
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="forEachSeries" />
|
|
|
+<a name="eachSeries" />
|
|
|
+### eachSeries(arr, iterator, callback)
|
|
|
+
|
|
|
+The same as [`each`](#each), only `iterator` is applied to each item in `arr` in
|
|
|
+series. The next `iterator` is only called once the current one has completed.
|
|
|
+This means the `iterator` functions will complete in order.
|
|
|
+
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="forEachLimit" />
|
|
|
+<a name="eachLimit" />
|
|
|
+### eachLimit(arr, limit, iterator, callback)
|
|
|
+
|
|
|
+The same as [`each`](#each), only no more than `limit` `iterator`s will be simultaneously
|
|
|
+running at any time.
|
|
|
+
|
|
|
+Note that the items in `arr` are not processed in batches, so there is no guarantee that
|
|
|
+the first `limit` `iterator` functions will complete before any others are started.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `arr` - An array to iterate over.
|
|
|
+* `limit` - The maximum number of `iterator`s to run at any time.
|
|
|
+* `iterator(item, callback)` - A function to apply to each item in `arr`.
|
|
|
+ The iterator is passed a `callback(err)` which must be called once it has
|
|
|
+ completed. If no error has occurred, the callback should be run without
|
|
|
+ arguments or with an explicit `null` argument.
|
|
|
+* `callback(err)` - A callback which is called when all `iterator` functions
|
|
|
+ have finished, or an error occurs.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+// Assume documents is an array of JSON objects and requestApi is a
|
|
|
+// function that interacts with a rate-limited REST api.
|
|
|
+
|
|
|
+async.eachLimit(documents, 20, requestApi, function(err){
|
|
|
+ // if any of the saves produced an error, err would equal that error
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="map" />
|
|
|
+### map(arr, iterator, callback)
|
|
|
+
|
|
|
+Produces a new array of values by mapping each value in `arr` through
|
|
|
+the `iterator` function. The `iterator` is called with an item from `arr` and a
|
|
|
+callback for when it has finished processing. Each of these callback takes 2 arguments:
|
|
|
+an `error`, and the transformed item from `arr`. If `iterator` passes an error to his
|
|
|
+callback, the main `callback` (for the `map` function) is immediately called with the error.
|
|
|
+
|
|
|
+Note, that since this function applies the `iterator` to each item in parallel,
|
|
|
+there is no guarantee that the `iterator` functions will complete in order.
|
|
|
+However, the results array will be in the same order as the original `arr`.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `arr` - An array to iterate over.
|
|
|
+* `iterator(item, callback)` - A function to apply to each item in `arr`.
|
|
|
+ The iterator is passed a `callback(err, transformed)` which must be called once
|
|
|
+ it has completed with an error (which can be `null`) and a transformed item.
|
|
|
+* `callback(err, results)` - A callback which is called when all `iterator`
|
|
|
+ functions have finished, or an error occurs. Results is an array of the
|
|
|
+ transformed items from the `arr`.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.map(['file1','file2','file3'], fs.stat, function(err, results){
|
|
|
+ // results is now an array of stats for each file
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="mapSeries" />
|
|
|
+### mapSeries(arr, iterator, callback)
|
|
|
+
|
|
|
+The same as [`map`](#map), only the `iterator` is applied to each item in `arr` in
|
|
|
+series. The next `iterator` is only called once the current one has completed.
|
|
|
+The results array will be in the same order as the original.
|
|
|
+
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="mapLimit" />
|
|
|
+### mapLimit(arr, limit, iterator, callback)
|
|
|
+
|
|
|
+The same as [`map`](#map), only no more than `limit` `iterator`s will be simultaneously
|
|
|
+running at any time.
|
|
|
+
|
|
|
+Note that the items are not processed in batches, so there is no guarantee that
|
|
|
+the first `limit` `iterator` functions will complete before any others are started.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `arr` - An array to iterate over.
|
|
|
+* `limit` - The maximum number of `iterator`s to run at any time.
|
|
|
+* `iterator(item, callback)` - A function to apply to each item in `arr`.
|
|
|
+ The iterator is passed a `callback(err, transformed)` which must be called once
|
|
|
+ it has completed with an error (which can be `null`) and a transformed item.
|
|
|
+* `callback(err, results)` - A callback which is called when all `iterator`
|
|
|
+ calls have finished, or an error occurs. The result is an array of the
|
|
|
+ transformed items from the original `arr`.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.mapLimit(['file1','file2','file3'], 1, fs.stat, function(err, results){
|
|
|
+ // results is now an array of stats for each file
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="select" />
|
|
|
+<a name="filter" />
|
|
|
+### filter(arr, iterator, callback)
|
|
|
+
|
|
|
+__Alias:__ `select`
|
|
|
+
|
|
|
+Returns a new array of all the values in `arr` which pass an async truth test.
|
|
|
+_The callback for each `iterator` call only accepts a single argument of `true` or
|
|
|
+`false`; it does not accept an error argument first!_ This is in-line with the
|
|
|
+way node libraries work with truth tests like `fs.exists`. This operation is
|
|
|
+performed in parallel, but the results array will be in the same order as the
|
|
|
+original.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `arr` - An array to iterate over.
|
|
|
+* `iterator(item, callback)` - A truth test to apply to each item in `arr`.
|
|
|
+ The `iterator` is passed a `callback(truthValue)`, which must be called with a
|
|
|
+ boolean argument once it has completed.
|
|
|
+* `callback(results)` - A callback which is called after all the `iterator`
|
|
|
+ functions have finished.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.filter(['file1','file2','file3'], fs.exists, function(results){
|
|
|
+ // results now equals an array of the existing files
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="selectSeries" />
|
|
|
+<a name="filterSeries" />
|
|
|
+### filterSeries(arr, iterator, callback)
|
|
|
+
|
|
|
+__Alias:__ `selectSeries`
|
|
|
+
|
|
|
+The same as [`filter`](#filter) only the `iterator` is applied to each item in `arr` in
|
|
|
+series. The next `iterator` is only called once the current one has completed.
|
|
|
+The results array will be in the same order as the original.
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="reject" />
|
|
|
+### reject(arr, iterator, callback)
|
|
|
+
|
|
|
+The opposite of [`filter`](#filter). Removes values that pass an `async` truth test.
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="rejectSeries" />
|
|
|
+### rejectSeries(arr, iterator, callback)
|
|
|
+
|
|
|
+The same as [`reject`](#reject), only the `iterator` is applied to each item in `arr`
|
|
|
+in series.
|
|
|
+
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="reduce" />
|
|
|
+### reduce(arr, memo, iterator, callback)
|
|
|
+
|
|
|
+__Aliases:__ `inject`, `foldl`
|
|
|
+
|
|
|
+Reduces `arr` into a single value using an async `iterator` to return
|
|
|
+each successive step. `memo` is the initial state of the reduction.
|
|
|
+This function only operates in series.
|
|
|
+
|
|
|
+For performance reasons, it may make sense to split a call to this function into
|
|
|
+a parallel map, and then use the normal `Array.prototype.reduce` on the results.
|
|
|
+This function is for situations where each step in the reduction needs to be async;
|
|
|
+if you can get the data before reducing it, then it's probably a good idea to do so.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `arr` - An array to iterate over.
|
|
|
+* `memo` - The initial state of the reduction.
|
|
|
+* `iterator(memo, item, callback)` - A function applied to each item in the
|
|
|
+ array to produce the next step in the reduction. The `iterator` is passed a
|
|
|
+ `callback(err, reduction)` which accepts an optional error as its first
|
|
|
+ argument, and the state of the reduction as the second. If an error is
|
|
|
+ passed to the callback, the reduction is stopped and the main `callback` is
|
|
|
+ immediately called with the error.
|
|
|
+* `callback(err, result)` - A callback which is called after all the `iterator`
|
|
|
+ functions have finished. Result is the reduced value.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.reduce([1,2,3], 0, function(memo, item, callback){
|
|
|
+ // pointless async:
|
|
|
+ process.nextTick(function(){
|
|
|
+ callback(null, memo + item)
|
|
|
+ });
|
|
|
+}, function(err, result){
|
|
|
+ // result is now equal to the last value of memo, which is 6
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="reduceRight" />
|
|
|
+### reduceRight(arr, memo, iterator, callback)
|
|
|
+
|
|
|
+__Alias:__ `foldr`
|
|
|
+
|
|
|
+Same as [`reduce`](#reduce), only operates on `arr` in reverse order.
|
|
|
+
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="detect" />
|
|
|
+### detect(arr, iterator, callback)
|
|
|
+
|
|
|
+Returns the first value in `arr` that passes an async truth test. The
|
|
|
+`iterator` is applied in parallel, meaning the first iterator to return `true` will
|
|
|
+fire the detect `callback` with that result. That means the result might not be
|
|
|
+the first item in the original `arr` (in terms of order) that passes the test.
|
|
|
+
|
|
|
+If order within the original `arr` is important, then look at [`detectSeries`](#detectSeries).
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `arr` - An array to iterate over.
|
|
|
+* `iterator(item, callback)` - A truth test to apply to each item in `arr`.
|
|
|
+ The iterator is passed a `callback(truthValue)` which must be called with a
|
|
|
+ boolean argument once it has completed.
|
|
|
+* `callback(result)` - A callback which is called as soon as any iterator returns
|
|
|
+ `true`, or after all the `iterator` functions have finished. Result will be
|
|
|
+ the first item in the array that passes the truth test (iterator) or the
|
|
|
+ value `undefined` if none passed.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.detect(['file1','file2','file3'], fs.exists, function(result){
|
|
|
+ // result now equals the first file in the list that exists
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="detectSeries" />
|
|
|
+### detectSeries(arr, iterator, callback)
|
|
|
+
|
|
|
+The same as [`detect`](#detect), only the `iterator` is applied to each item in `arr`
|
|
|
+in series. This means the result is always the first in the original `arr` (in
|
|
|
+terms of array order) that passes the truth test.
|
|
|
+
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="sortBy" />
|
|
|
+### sortBy(arr, iterator, callback)
|
|
|
+
|
|
|
+Sorts a list by the results of running each `arr` value through an async `iterator`.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `arr` - An array to iterate over.
|
|
|
+* `iterator(item, callback)` - A function to apply to each item in `arr`.
|
|
|
+ The iterator is passed a `callback(err, sortValue)` which must be called once it
|
|
|
+ has completed with an error (which can be `null`) and a value to use as the sort
|
|
|
+ criteria.
|
|
|
+* `callback(err, results)` - A callback which is called after all the `iterator`
|
|
|
+ functions have finished, or an error occurs. Results is the items from
|
|
|
+ the original `arr` sorted by the values returned by the `iterator` calls.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.sortBy(['file1','file2','file3'], function(file, callback){
|
|
|
+ fs.stat(file, function(err, stats){
|
|
|
+ callback(err, stats.mtime);
|
|
|
+ });
|
|
|
+}, function(err, results){
|
|
|
+ // results is now the original array of files sorted by
|
|
|
+ // modified date
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+__Sort Order__
|
|
|
+
|
|
|
+By modifying the callback parameter the sorting order can be influenced:
|
|
|
+
|
|
|
+```js
|
|
|
+//ascending order
|
|
|
+async.sortBy([1,9,3,5], function(x, callback){
|
|
|
+ callback(null, x);
|
|
|
+}, function(err,result){
|
|
|
+ //result callback
|
|
|
+} );
|
|
|
+
|
|
|
+//descending order
|
|
|
+async.sortBy([1,9,3,5], function(x, callback){
|
|
|
+ callback(null, x*-1); //<- x*-1 instead of x, turns the order around
|
|
|
+}, function(err,result){
|
|
|
+ //result callback
|
|
|
+} );
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="some" />
|
|
|
+### some(arr, iterator, callback)
|
|
|
+
|
|
|
+__Alias:__ `any`
|
|
|
+
|
|
|
+Returns `true` if at least one element in the `arr` satisfies an async test.
|
|
|
+_The callback for each iterator call only accepts a single argument of `true` or
|
|
|
+`false`; it does not accept an error argument first!_ This is in-line with the
|
|
|
+way node libraries work with truth tests like `fs.exists`. Once any iterator
|
|
|
+call returns `true`, the main `callback` is immediately called.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `arr` - An array to iterate over.
|
|
|
+* `iterator(item, callback)` - A truth test to apply to each item in the array
|
|
|
+ in parallel. The iterator is passed a callback(truthValue) which must be
|
|
|
+ called with a boolean argument once it has completed.
|
|
|
+* `callback(result)` - A callback which is called as soon as any iterator returns
|
|
|
+ `true`, or after all the iterator functions have finished. Result will be
|
|
|
+ either `true` or `false` depending on the values of the async tests.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.some(['file1','file2','file3'], fs.exists, function(result){
|
|
|
+ // if result is true then at least one of the files exists
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="every" />
|
|
|
+### every(arr, iterator, callback)
|
|
|
+
|
|
|
+__Alias:__ `all`
|
|
|
+
|
|
|
+Returns `true` if every element in `arr` satisfies an async test.
|
|
|
+_The callback for each `iterator` call only accepts a single argument of `true` or
|
|
|
+`false`; it does not accept an error argument first!_ This is in-line with the
|
|
|
+way node libraries work with truth tests like `fs.exists`.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `arr` - An array to iterate over.
|
|
|
+* `iterator(item, callback)` - A truth test to apply to each item in the array
|
|
|
+ in parallel. The iterator is passed a callback(truthValue) which must be
|
|
|
+ called with a boolean argument once it has completed.
|
|
|
+* `callback(result)` - A callback which is called after all the `iterator`
|
|
|
+ functions have finished. Result will be either `true` or `false` depending on
|
|
|
+ the values of the async tests.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.every(['file1','file2','file3'], fs.exists, function(result){
|
|
|
+ // if result is true then every file exists
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="concat" />
|
|
|
+### concat(arr, iterator, callback)
|
|
|
+
|
|
|
+Applies `iterator` to each item in `arr`, concatenating the results. Returns the
|
|
|
+concatenated list. The `iterator`s are called in parallel, and the results are
|
|
|
+concatenated as they return. There is no guarantee that the results array will
|
|
|
+be returned in the original order of `arr` passed to the `iterator` function.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `arr` - An array to iterate over.
|
|
|
+* `iterator(item, callback)` - A function to apply to each item in `arr`.
|
|
|
+ The iterator is passed a `callback(err, results)` which must be called once it
|
|
|
+ has completed with an error (which can be `null`) and an array of results.
|
|
|
+* `callback(err, results)` - A callback which is called after all the `iterator`
|
|
|
+ functions have finished, or an error occurs. Results is an array containing
|
|
|
+ the concatenated results of the `iterator` function.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){
|
|
|
+ // files is now a list of filenames that exist in the 3 directories
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="concatSeries" />
|
|
|
+### concatSeries(arr, iterator, callback)
|
|
|
+
|
|
|
+Same as [`concat`](#concat), but executes in series instead of parallel.
|
|
|
+
|
|
|
+
|
|
|
+## Control Flow
|
|
|
+
|
|
|
+<a name="series" />
|
|
|
+### series(tasks, [callback])
|
|
|
+
|
|
|
+Run the functions in the `tasks` array in series, each one running once the previous
|
|
|
+function has completed. If any functions in the series pass an error to its
|
|
|
+callback, no more functions are run, and `callback` is immediately called with the value of the error.
|
|
|
+Otherwise, `callback` receives an array of results when `tasks` have completed.
|
|
|
+
|
|
|
+It is also possible to use an object instead of an array. Each property will be
|
|
|
+run as a function, and the results will be passed to the final `callback` as an object
|
|
|
+instead of an array. This can be a more readable way of handling results from
|
|
|
+[`series`](#series).
|
|
|
+
|
|
|
+**Note** that while many implementations preserve the order of object properties, the
|
|
|
+[ECMAScript Language Specifcation](http://www.ecma-international.org/ecma-262/5.1/#sec-8.6)
|
|
|
+explicitly states that
|
|
|
+
|
|
|
+> The mechanics and order of enumerating the properties is not specified.
|
|
|
+
|
|
|
+So if you rely on the order in which your series of functions are executed, and want
|
|
|
+this to work on all platforms, consider using an array.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `tasks` - An array or object containing functions to run, each function is passed
|
|
|
+ a `callback(err, result)` it must call on completion with an error `err` (which can
|
|
|
+ be `null`) and an optional `result` value.
|
|
|
+* `callback(err, results)` - An optional callback to run once all the functions
|
|
|
+ have completed. This function gets a results array (or object) containing all
|
|
|
+ the result arguments passed to the `task` callbacks.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.series([
|
|
|
+ function(callback){
|
|
|
+ // do some stuff ...
|
|
|
+ callback(null, 'one');
|
|
|
+ },
|
|
|
+ function(callback){
|
|
|
+ // do some more stuff ...
|
|
|
+ callback(null, 'two');
|
|
|
+ }
|
|
|
+],
|
|
|
+// optional callback
|
|
|
+function(err, results){
|
|
|
+ // results is now equal to ['one', 'two']
|
|
|
+});
|
|
|
+
|
|
|
+
|
|
|
+// an example using an object instead of an array
|
|
|
+async.series({
|
|
|
+ one: function(callback){
|
|
|
+ setTimeout(function(){
|
|
|
+ callback(null, 1);
|
|
|
+ }, 200);
|
|
|
+ },
|
|
|
+ two: function(callback){
|
|
|
+ setTimeout(function(){
|
|
|
+ callback(null, 2);
|
|
|
+ }, 100);
|
|
|
+ }
|
|
|
+},
|
|
|
+function(err, results) {
|
|
|
+ // results is now equal to: {one: 1, two: 2}
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="parallel" />
|
|
|
+### parallel(tasks, [callback])
|
|
|
+
|
|
|
+Run the `tasks` array of functions in parallel, without waiting until the previous
|
|
|
+function has completed. If any of the functions pass an error to its
|
|
|
+callback, the main `callback` is immediately called with the value of the error.
|
|
|
+Once the `tasks` have completed, the results are passed to the final `callback` as an
|
|
|
+array.
|
|
|
+
|
|
|
+It is also possible to use an object instead of an array. Each property will be
|
|
|
+run as a function and the results will be passed to the final `callback` as an object
|
|
|
+instead of an array. This can be a more readable way of handling results from
|
|
|
+[`parallel`](#parallel).
|
|
|
+
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `tasks` - An array or object containing functions to run. Each function is passed
|
|
|
+ a `callback(err, result)` which it must call on completion with an error `err`
|
|
|
+ (which can be `null`) and an optional `result` value.
|
|
|
+* `callback(err, results)` - An optional callback to run once all the functions
|
|
|
+ have completed. This function gets a results array (or object) containing all
|
|
|
+ the result arguments passed to the task callbacks.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.parallel([
|
|
|
+ function(callback){
|
|
|
+ setTimeout(function(){
|
|
|
+ callback(null, 'one');
|
|
|
+ }, 200);
|
|
|
+ },
|
|
|
+ function(callback){
|
|
|
+ setTimeout(function(){
|
|
|
+ callback(null, 'two');
|
|
|
+ }, 100);
|
|
|
+ }
|
|
|
+],
|
|
|
+// optional callback
|
|
|
+function(err, results){
|
|
|
+ // the results array will equal ['one','two'] even though
|
|
|
+ // the second function had a shorter timeout.
|
|
|
+});
|
|
|
+
|
|
|
+
|
|
|
+// an example using an object instead of an array
|
|
|
+async.parallel({
|
|
|
+ one: function(callback){
|
|
|
+ setTimeout(function(){
|
|
|
+ callback(null, 1);
|
|
|
+ }, 200);
|
|
|
+ },
|
|
|
+ two: function(callback){
|
|
|
+ setTimeout(function(){
|
|
|
+ callback(null, 2);
|
|
|
+ }, 100);
|
|
|
+ }
|
|
|
+},
|
|
|
+function(err, results) {
|
|
|
+ // results is now equals to: {one: 1, two: 2}
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="parallelLimit" />
|
|
|
+### parallelLimit(tasks, limit, [callback])
|
|
|
+
|
|
|
+The same as [`parallel`](#parallel), only `tasks` are executed in parallel
|
|
|
+with a maximum of `limit` tasks executing at any time.
|
|
|
+
|
|
|
+Note that the `tasks` are not executed in batches, so there is no guarantee that
|
|
|
+the first `limit` tasks will complete before any others are started.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `tasks` - An array or object containing functions to run, each function is passed
|
|
|
+ a `callback(err, result)` it must call on completion with an error `err` (which can
|
|
|
+ be `null`) and an optional `result` value.
|
|
|
+* `limit` - The maximum number of `tasks` to run at any time.
|
|
|
+* `callback(err, results)` - An optional callback to run once all the functions
|
|
|
+ have completed. This function gets a results array (or object) containing all
|
|
|
+ the result arguments passed to the `task` callbacks.
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="whilst" />
|
|
|
+### whilst(test, fn, callback)
|
|
|
+
|
|
|
+Repeatedly call `fn`, while `test` returns `true`. Calls `callback` when stopped,
|
|
|
+or an error occurs.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `test()` - synchronous truth test to perform before each execution of `fn`.
|
|
|
+* `fn(callback)` - A function which is called each time `test` passes. The function is
|
|
|
+ passed a `callback(err)`, which must be called once it has completed with an
|
|
|
+ optional `err` argument.
|
|
|
+* `callback(err)` - A callback which is called after the test fails and repeated
|
|
|
+ execution of `fn` has stopped.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+var count = 0;
|
|
|
+
|
|
|
+async.whilst(
|
|
|
+ function () { return count < 5; },
|
|
|
+ function (callback) {
|
|
|
+ count++;
|
|
|
+ setTimeout(callback, 1000);
|
|
|
+ },
|
|
|
+ function (err) {
|
|
|
+ // 5 seconds have passed
|
|
|
+ }
|
|
|
+);
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="doWhilst" />
|
|
|
+### doWhilst(fn, test, callback)
|
|
|
+
|
|
|
+The post-check version of [`whilst`](#whilst). To reflect the difference in
|
|
|
+the order of operations, the arguments `test` and `fn` are switched.
|
|
|
+
|
|
|
+`doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript.
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="until" />
|
|
|
+### until(test, fn, callback)
|
|
|
+
|
|
|
+Repeatedly call `fn` until `test` returns `true`. Calls `callback` when stopped,
|
|
|
+or an error occurs.
|
|
|
+
|
|
|
+The inverse of [`whilst`](#whilst).
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="doUntil" />
|
|
|
+### doUntil(fn, test, callback)
|
|
|
+
|
|
|
+Like [`doWhilst`](#doWhilst), except the `test` is inverted. Note the argument ordering differs from `until`.
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="forever" />
|
|
|
+### forever(fn, errback)
|
|
|
+
|
|
|
+Calls the asynchronous function `fn` with a callback parameter that allows it to
|
|
|
+call itself again, in series, indefinitely.
|
|
|
+
|
|
|
+If an error is passed to the callback then `errback` is called with the
|
|
|
+error, and execution stops, otherwise it will never be called.
|
|
|
+
|
|
|
+```js
|
|
|
+async.forever(
|
|
|
+ function(next) {
|
|
|
+ // next is suitable for passing to things that need a callback(err [, whatever]);
|
|
|
+ // it will result in this function being called again.
|
|
|
+ },
|
|
|
+ function(err) {
|
|
|
+ // if next is called with a value in its first parameter, it will appear
|
|
|
+ // in here as 'err', and execution will stop.
|
|
|
+ }
|
|
|
+);
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="waterfall" />
|
|
|
+### waterfall(tasks, [callback])
|
|
|
+
|
|
|
+Runs the `tasks` array of functions in series, each passing their results to the next in
|
|
|
+the array. However, if any of the `tasks` pass an error to their own callback, the
|
|
|
+next function is not executed, and the main `callback` is immediately called with
|
|
|
+the error.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `tasks` - An array of functions to run, each function is passed a
|
|
|
+ `callback(err, result1, result2, ...)` it must call on completion. The first
|
|
|
+ argument is an error (which can be `null`) and any further arguments will be
|
|
|
+ passed as arguments in order to the next task.
|
|
|
+* `callback(err, [results])` - An optional callback to run once all the functions
|
|
|
+ have completed. This will be passed the results of the last task's callback.
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.waterfall([
|
|
|
+ function(callback) {
|
|
|
+ callback(null, 'one', 'two');
|
|
|
+ },
|
|
|
+ function(arg1, arg2, callback) {
|
|
|
+ // arg1 now equals 'one' and arg2 now equals 'two'
|
|
|
+ callback(null, 'three');
|
|
|
+ },
|
|
|
+ function(arg1, callback) {
|
|
|
+ // arg1 now equals 'three'
|
|
|
+ callback(null, 'done');
|
|
|
+ }
|
|
|
+], function (err, result) {
|
|
|
+ // result now equals 'done'
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+<a name="compose" />
|
|
|
+### compose(fn1, fn2...)
|
|
|
+
|
|
|
+Creates a function which is a composition of the passed asynchronous
|
|
|
+functions. Each function consumes the return value of the function that
|
|
|
+follows. Composing functions `f()`, `g()`, and `h()` would produce the result of
|
|
|
+`f(g(h()))`, only this version uses callbacks to obtain the return values.
|
|
|
+
|
|
|
+Each function is executed with the `this` binding of the composed function.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `functions...` - the asynchronous functions to compose
|
|
|
+
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+function add1(n, callback) {
|
|
|
+ setTimeout(function () {
|
|
|
+ callback(null, n + 1);
|
|
|
+ }, 10);
|
|
|
+}
|
|
|
+
|
|
|
+function mul3(n, callback) {
|
|
|
+ setTimeout(function () {
|
|
|
+ callback(null, n * 3);
|
|
|
+ }, 10);
|
|
|
+}
|
|
|
+
|
|
|
+var add1mul3 = async.compose(mul3, add1);
|
|
|
+
|
|
|
+add1mul3(4, function (err, result) {
|
|
|
+ // result now equals 15
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+<a name="seq" />
|
|
|
+### seq(fn1, fn2...)
|
|
|
+
|
|
|
+Version of the compose function that is more natural to read.
|
|
|
+Each function consumes the return value of the previous function.
|
|
|
+It is the equivalent of [`compose`](#compose) with the arguments reversed.
|
|
|
+
|
|
|
+Each function is executed with the `this` binding of the composed function.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* functions... - the asynchronous functions to compose
|
|
|
+
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+// Requires lodash (or underscore), express3 and dresende's orm2.
|
|
|
+// Part of an app, that fetches cats of the logged user.
|
|
|
+// This example uses `seq` function to avoid overnesting and error
|
|
|
+// handling clutter.
|
|
|
+app.get('/cats', function(request, response) {
|
|
|
+ var User = request.models.User;
|
|
|
+ async.seq(
|
|
|
+ _.bind(User.get, User), // 'User.get' has signature (id, callback(err, data))
|
|
|
+ function(user, fn) {
|
|
|
+ user.getCats(fn); // 'getCats' has signature (callback(err, data))
|
|
|
+ }
|
|
|
+ )(req.session.user_id, function (err, cats) {
|
|
|
+ if (err) {
|
|
|
+ console.error(err);
|
|
|
+ response.json({ status: 'error', message: err.message });
|
|
|
+ } else {
|
|
|
+ response.json({ status: 'ok', message: 'Cats found', data: cats });
|
|
|
+ }
|
|
|
+ });
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+<a name="applyEach" />
|
|
|
+### applyEach(fns, args..., callback)
|
|
|
+
|
|
|
+Applies the provided arguments to each function in the array, calling
|
|
|
+`callback` after all functions have completed. If you only provide the first
|
|
|
+argument, then it will return a function which lets you pass in the
|
|
|
+arguments as if it were a single function call.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `fns` - the asynchronous functions to all call with the same arguments
|
|
|
+* `args...` - any number of separate arguments to pass to the function
|
|
|
+* `callback` - the final argument should be the callback, called when all
|
|
|
+ functions have completed processing
|
|
|
+
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.applyEach([enableSearch, updateSchema], 'bucket', callback);
|
|
|
+
|
|
|
+// partial application example:
|
|
|
+async.each(
|
|
|
+ buckets,
|
|
|
+ async.applyEach([enableSearch, updateSchema]),
|
|
|
+ callback
|
|
|
+);
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="applyEachSeries" />
|
|
|
+### applyEachSeries(arr, iterator, callback)
|
|
|
+
|
|
|
+The same as [`applyEach`](#applyEach) only the functions are applied in series.
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="queue" />
|
|
|
+### queue(worker, concurrency)
|
|
|
+
|
|
|
+Creates a `queue` object with the specified `concurrency`. Tasks added to the
|
|
|
+`queue` are processed in parallel (up to the `concurrency` limit). If all
|
|
|
+`worker`s are in progress, the task is queued until one becomes available.
|
|
|
+Once a `worker` completes a `task`, that `task`'s callback is called.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `worker(task, callback)` - An asynchronous function for processing a queued
|
|
|
+ task, which must call its `callback(err)` argument when finished, with an
|
|
|
+ optional `error` as an argument.
|
|
|
+* `concurrency` - An `integer` for determining how many `worker` functions should be
|
|
|
+ run in parallel.
|
|
|
+
|
|
|
+__Queue objects__
|
|
|
+
|
|
|
+The `queue` object returned by this function has the following properties and
|
|
|
+methods:
|
|
|
+
|
|
|
+* `length()` - a function returning the number of items waiting to be processed.
|
|
|
+* `started` - a function returning whether or not any items have been pushed and processed by the queue
|
|
|
+* `running()` - a function returning the number of items currently being processed.
|
|
|
+* `idle()` - a function returning false if there are items waiting or being processed, or true if not.
|
|
|
+* `concurrency` - an integer for determining how many `worker` functions should be
|
|
|
+ run in parallel. This property can be changed after a `queue` is created to
|
|
|
+ alter the concurrency on-the-fly.
|
|
|
+* `push(task, [callback])` - add a new task to the `queue`. Calls `callback` once
|
|
|
+ the `worker` has finished processing the task. Instead of a single task, a `tasks` array
|
|
|
+ can be submitted. The respective callback is used for every task in the list.
|
|
|
+* `unshift(task, [callback])` - add a new task to the front of the `queue`.
|
|
|
+* `saturated` - a callback that is called when the `queue` length hits the `concurrency` limit,
|
|
|
+ and further tasks will be queued.
|
|
|
+* `empty` - a callback that is called when the last item from the `queue` is given to a `worker`.
|
|
|
+* `drain` - a callback that is called when the last item from the `queue` has returned from the `worker`.
|
|
|
+* `paused` - a boolean for determining whether the queue is in a paused state
|
|
|
+* `pause()` - a function that pauses the processing of tasks until `resume()` is called.
|
|
|
+* `resume()` - a function that resumes the processing of queued tasks when the queue is paused.
|
|
|
+* `kill()` - a function that removes the `drain` callback and empties remaining tasks from the queue forcing it to go idle.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+// create a queue object with concurrency 2
|
|
|
+
|
|
|
+var q = async.queue(function (task, callback) {
|
|
|
+ console.log('hello ' + task.name);
|
|
|
+ callback();
|
|
|
+}, 2);
|
|
|
+
|
|
|
+
|
|
|
+// assign a callback
|
|
|
+q.drain = function() {
|
|
|
+ console.log('all items have been processed');
|
|
|
+}
|
|
|
+
|
|
|
+// add some items to the queue
|
|
|
+
|
|
|
+q.push({name: 'foo'}, function (err) {
|
|
|
+ console.log('finished processing foo');
|
|
|
+});
|
|
|
+q.push({name: 'bar'}, function (err) {
|
|
|
+ console.log('finished processing bar');
|
|
|
+});
|
|
|
+
|
|
|
+// add some items to the queue (batch-wise)
|
|
|
+
|
|
|
+q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) {
|
|
|
+ console.log('finished processing item');
|
|
|
+});
|
|
|
+
|
|
|
+// add some items to the front of the queue
|
|
|
+
|
|
|
+q.unshift({name: 'bar'}, function (err) {
|
|
|
+ console.log('finished processing bar');
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="priorityQueue" />
|
|
|
+### priorityQueue(worker, concurrency)
|
|
|
+
|
|
|
+The same as [`queue`](#queue) only tasks are assigned a priority and completed in ascending priority order. There are two differences between `queue` and `priorityQueue` objects:
|
|
|
+
|
|
|
+* `push(task, priority, [callback])` - `priority` should be a number. If an array of
|
|
|
+ `tasks` is given, all tasks will be assigned the same priority.
|
|
|
+* The `unshift` method was removed.
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="cargo" />
|
|
|
+### cargo(worker, [payload])
|
|
|
+
|
|
|
+Creates a `cargo` object with the specified payload. Tasks added to the
|
|
|
+cargo will be processed altogether (up to the `payload` limit). If the
|
|
|
+`worker` is in progress, the task is queued until it becomes available. Once
|
|
|
+the `worker` has completed some tasks, each callback of those tasks is called.
|
|
|
+Check out [this animation](https://camo.githubusercontent.com/6bbd36f4cf5b35a0f11a96dcd2e97711ffc2fb37/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130382f62626330636662302d356632392d313165322d393734662d3333393763363464633835382e676966) for how `cargo` and `queue` work.
|
|
|
+
|
|
|
+While [queue](#queue) passes only one task to one of a group of workers
|
|
|
+at a time, cargo passes an array of tasks to a single worker, repeating
|
|
|
+when the worker is finished.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `worker(tasks, callback)` - An asynchronous function for processing an array of
|
|
|
+ queued tasks, which must call its `callback(err)` argument when finished, with
|
|
|
+ an optional `err` argument.
|
|
|
+* `payload` - An optional `integer` for determining how many tasks should be
|
|
|
+ processed per round; if omitted, the default is unlimited.
|
|
|
+
|
|
|
+__Cargo objects__
|
|
|
+
|
|
|
+The `cargo` object returned by this function has the following properties and
|
|
|
+methods:
|
|
|
+
|
|
|
+* `length()` - A function returning the number of items waiting to be processed.
|
|
|
+* `payload` - An `integer` for determining how many tasks should be
|
|
|
+ process per round. This property can be changed after a `cargo` is created to
|
|
|
+ alter the payload on-the-fly.
|
|
|
+* `push(task, [callback])` - Adds `task` to the `queue`. The callback is called
|
|
|
+ once the `worker` has finished processing the task. Instead of a single task, an array of `tasks`
|
|
|
+ can be submitted. The respective callback is used for every task in the list.
|
|
|
+* `saturated` - A callback that is called when the `queue.length()` hits the concurrency and further tasks will be queued.
|
|
|
+* `empty` - A callback that is called when the last item from the `queue` is given to a `worker`.
|
|
|
+* `drain` - A callback that is called when the last item from the `queue` has returned from the `worker`.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+// create a cargo object with payload 2
|
|
|
+
|
|
|
+var cargo = async.cargo(function (tasks, callback) {
|
|
|
+ for(var i=0; i<tasks.length; i++){
|
|
|
+ console.log('hello ' + tasks[i].name);
|
|
|
+ }
|
|
|
+ callback();
|
|
|
+}, 2);
|
|
|
+
|
|
|
+
|
|
|
+// add some items
|
|
|
+
|
|
|
+cargo.push({name: 'foo'}, function (err) {
|
|
|
+ console.log('finished processing foo');
|
|
|
+});
|
|
|
+cargo.push({name: 'bar'}, function (err) {
|
|
|
+ console.log('finished processing bar');
|
|
|
+});
|
|
|
+cargo.push({name: 'baz'}, function (err) {
|
|
|
+ console.log('finished processing baz');
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="auto" />
|
|
|
+### auto(tasks, [callback])
|
|
|
+
|
|
|
+Determines the best order for running the functions in `tasks`, based on their
|
|
|
+requirements. Each function can optionally depend on other functions being completed
|
|
|
+first, and each function is run as soon as its requirements are satisfied.
|
|
|
+
|
|
|
+If any of the functions pass an error to their callback, it will not
|
|
|
+complete (so any other functions depending on it will not run), and the main
|
|
|
+`callback` is immediately called with the error. Functions also receive an
|
|
|
+object containing the results of functions which have completed so far.
|
|
|
+
|
|
|
+Note, all functions are called with a `results` object as a second argument,
|
|
|
+so it is unsafe to pass functions in the `tasks` object which cannot handle the
|
|
|
+extra argument.
|
|
|
+
|
|
|
+For example, this snippet of code:
|
|
|
+
|
|
|
+```js
|
|
|
+async.auto({
|
|
|
+ readData: async.apply(fs.readFile, 'data.txt', 'utf-8')
|
|
|
+}, callback);
|
|
|
+```
|
|
|
+
|
|
|
+will have the effect of calling `readFile` with the results object as the last
|
|
|
+argument, which will fail:
|
|
|
+
|
|
|
+```js
|
|
|
+fs.readFile('data.txt', 'utf-8', cb, {});
|
|
|
+```
|
|
|
+
|
|
|
+Instead, wrap the call to `readFile` in a function which does not forward the
|
|
|
+`results` object:
|
|
|
+
|
|
|
+```js
|
|
|
+async.auto({
|
|
|
+ readData: function(cb, results){
|
|
|
+ fs.readFile('data.txt', 'utf-8', cb);
|
|
|
+ }
|
|
|
+}, callback);
|
|
|
+```
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `tasks` - An object. Each of its properties is either a function or an array of
|
|
|
+ requirements, with the function itself the last item in the array. The object's key
|
|
|
+ of a property serves as the name of the task defined by that property,
|
|
|
+ i.e. can be used when specifying requirements for other tasks.
|
|
|
+ The function receives two arguments: (1) a `callback(err, result)` which must be
|
|
|
+ called when finished, passing an `error` (which can be `null`) and the result of
|
|
|
+ the function's execution, and (2) a `results` object, containing the results of
|
|
|
+ the previously executed functions.
|
|
|
+* `callback(err, results)` - An optional callback which is called when all the
|
|
|
+ tasks have been completed. It receives the `err` argument if any `tasks`
|
|
|
+ pass an error to their callback. Results are always returned; however, if
|
|
|
+ an error occurs, no further `tasks` will be performed, and the results
|
|
|
+ object will only contain partial results.
|
|
|
+
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+async.auto({
|
|
|
+ get_data: function(callback){
|
|
|
+ console.log('in get_data');
|
|
|
+ // async code to get some data
|
|
|
+ callback(null, 'data', 'converted to array');
|
|
|
+ },
|
|
|
+ make_folder: function(callback){
|
|
|
+ console.log('in make_folder');
|
|
|
+ // async code to create a directory to store a file in
|
|
|
+ // this is run at the same time as getting the data
|
|
|
+ callback(null, 'folder');
|
|
|
+ },
|
|
|
+ write_file: ['get_data', 'make_folder', function(callback, results){
|
|
|
+ console.log('in write_file', JSON.stringify(results));
|
|
|
+ // once there is some data and the directory exists,
|
|
|
+ // write the data to a file in the directory
|
|
|
+ callback(null, 'filename');
|
|
|
+ }],
|
|
|
+ email_link: ['write_file', function(callback, results){
|
|
|
+ console.log('in email_link', JSON.stringify(results));
|
|
|
+ // once the file is written let's email a link to it...
|
|
|
+ // results.write_file contains the filename returned by write_file.
|
|
|
+ callback(null, {'file':results.write_file, 'email':'[email protected]'});
|
|
|
+ }]
|
|
|
+}, function(err, results) {
|
|
|
+ console.log('err = ', err);
|
|
|
+ console.log('results = ', results);
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+This is a fairly trivial example, but to do this using the basic parallel and
|
|
|
+series functions would look like this:
|
|
|
+
|
|
|
+```js
|
|
|
+async.parallel([
|
|
|
+ function(callback){
|
|
|
+ console.log('in get_data');
|
|
|
+ // async code to get some data
|
|
|
+ callback(null, 'data', 'converted to array');
|
|
|
+ },
|
|
|
+ function(callback){
|
|
|
+ console.log('in make_folder');
|
|
|
+ // async code to create a directory to store a file in
|
|
|
+ // this is run at the same time as getting the data
|
|
|
+ callback(null, 'folder');
|
|
|
+ }
|
|
|
+],
|
|
|
+function(err, results){
|
|
|
+ async.series([
|
|
|
+ function(callback){
|
|
|
+ console.log('in write_file', JSON.stringify(results));
|
|
|
+ // once there is some data and the directory exists,
|
|
|
+ // write the data to a file in the directory
|
|
|
+ results.push('filename');
|
|
|
+ callback(null);
|
|
|
+ },
|
|
|
+ function(callback){
|
|
|
+ console.log('in email_link', JSON.stringify(results));
|
|
|
+ // once the file is written let's email a link to it...
|
|
|
+ callback(null, {'file':results.pop(), 'email':'[email protected]'});
|
|
|
+ }
|
|
|
+ ]);
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+For a complicated series of `async` tasks, using the [`auto`](#auto) function makes adding
|
|
|
+new tasks much easier (and the code more readable).
|
|
|
+
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="retry" />
|
|
|
+### retry([times = 5], task, [callback])
|
|
|
+
|
|
|
+Attempts to get a successful response from `task` no more than `times` times before
|
|
|
+returning an error. If the task is successful, the `callback` will be passed the result
|
|
|
+of the successful task. If all attempts fail, the callback will be passed the error and
|
|
|
+result (if any) of the final attempt.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `times` - An integer indicating how many times to attempt the `task` before giving up. Defaults to 5.
|
|
|
+* `task(callback, results)` - A function which receives two arguments: (1) a `callback(err, result)`
|
|
|
+ which must be called when finished, passing `err` (which can be `null`) and the `result` of
|
|
|
+ the function's execution, and (2) a `results` object, containing the results of
|
|
|
+ the previously executed functions (if nested inside another control flow).
|
|
|
+* `callback(err, results)` - An optional callback which is called when the
|
|
|
+ task has succeeded, or after the final failed attempt. It receives the `err` and `result` arguments of the last attempt at completing the `task`.
|
|
|
+
|
|
|
+The [`retry`](#retry) function can be used as a stand-alone control flow by passing a
|
|
|
+callback, as shown below:
|
|
|
+
|
|
|
+```js
|
|
|
+async.retry(3, apiMethod, function(err, result) {
|
|
|
+ // do something with the result
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+It can also be embeded within other control flow functions to retry individual methods
|
|
|
+that are not as reliable, like this:
|
|
|
+
|
|
|
+```js
|
|
|
+async.auto({
|
|
|
+ users: api.getUsers.bind(api),
|
|
|
+ payments: async.retry(3, api.getPayments.bind(api))
|
|
|
+}, function(err, results) {
|
|
|
+ // do something with the results
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="iterator" />
|
|
|
+### iterator(tasks)
|
|
|
+
|
|
|
+Creates an iterator function which calls the next function in the `tasks` array,
|
|
|
+returning a continuation to call the next one after that. It's also possible to
|
|
|
+“peek” at the next iterator with `iterator.next()`.
|
|
|
+
|
|
|
+This function is used internally by the `async` module, but can be useful when
|
|
|
+you want to manually control the flow of functions in series.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `tasks` - An array of functions to run.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+var iterator = async.iterator([
|
|
|
+ function(){ sys.p('one'); },
|
|
|
+ function(){ sys.p('two'); },
|
|
|
+ function(){ sys.p('three'); }
|
|
|
+]);
|
|
|
+
|
|
|
+node> var iterator2 = iterator();
|
|
|
+'one'
|
|
|
+node> var iterator3 = iterator2();
|
|
|
+'two'
|
|
|
+node> iterator3();
|
|
|
+'three'
|
|
|
+node> var nextfn = iterator2.next();
|
|
|
+node> nextfn();
|
|
|
+'three'
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="apply" />
|
|
|
+### apply(function, arguments..)
|
|
|
+
|
|
|
+Creates a continuation function with some arguments already applied.
|
|
|
+
|
|
|
+Useful as a shorthand when combined with other control flow functions. Any arguments
|
|
|
+passed to the returned function are added to the arguments originally passed
|
|
|
+to apply.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `function` - The function you want to eventually apply all arguments to.
|
|
|
+* `arguments...` - Any number of arguments to automatically apply when the
|
|
|
+ continuation is called.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+// using apply
|
|
|
+
|
|
|
+async.parallel([
|
|
|
+ async.apply(fs.writeFile, 'testfile1', 'test1'),
|
|
|
+ async.apply(fs.writeFile, 'testfile2', 'test2'),
|
|
|
+]);
|
|
|
+
|
|
|
+
|
|
|
+// the same process without using apply
|
|
|
+
|
|
|
+async.parallel([
|
|
|
+ function(callback){
|
|
|
+ fs.writeFile('testfile1', 'test1', callback);
|
|
|
+ },
|
|
|
+ function(callback){
|
|
|
+ fs.writeFile('testfile2', 'test2', callback);
|
|
|
+ }
|
|
|
+]);
|
|
|
+```
|
|
|
+
|
|
|
+It's possible to pass any number of additional arguments when calling the
|
|
|
+continuation:
|
|
|
+
|
|
|
+```js
|
|
|
+node> var fn = async.apply(sys.puts, 'one');
|
|
|
+node> fn('two', 'three');
|
|
|
+one
|
|
|
+two
|
|
|
+three
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="nextTick" />
|
|
|
+### nextTick(callback), setImmediate(callback)
|
|
|
+
|
|
|
+Calls `callback` on a later loop around the event loop. In Node.js this just
|
|
|
+calls `process.nextTick`; in the browser it falls back to `setImmediate(callback)`
|
|
|
+if available, otherwise `setTimeout(callback, 0)`, which means other higher priority
|
|
|
+events may precede the execution of `callback`.
|
|
|
+
|
|
|
+This is used internally for browser-compatibility purposes.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `callback` - The function to call on a later loop around the event loop.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+var call_order = [];
|
|
|
+async.nextTick(function(){
|
|
|
+ call_order.push('two');
|
|
|
+ // call_order now equals ['one','two']
|
|
|
+});
|
|
|
+call_order.push('one')
|
|
|
+```
|
|
|
+
|
|
|
+<a name="times" />
|
|
|
+### times(n, callback)
|
|
|
+
|
|
|
+Calls the `callback` function `n` times, and accumulates results in the same manner
|
|
|
+you would use with [`map`](#map).
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `n` - The number of times to run the function.
|
|
|
+* `callback` - The function to call `n` times.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+// Pretend this is some complicated async factory
|
|
|
+var createUser = function(id, callback) {
|
|
|
+ callback(null, {
|
|
|
+ id: 'user' + id
|
|
|
+ })
|
|
|
+}
|
|
|
+// generate 5 users
|
|
|
+async.times(5, function(n, next){
|
|
|
+ createUser(n, function(err, user) {
|
|
|
+ next(err, user)
|
|
|
+ })
|
|
|
+}, function(err, users) {
|
|
|
+ // we should now have 5 users
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+<a name="timesSeries" />
|
|
|
+### timesSeries(n, callback)
|
|
|
+
|
|
|
+The same as [`times`](#times), only the iterator is applied to each item in `arr` in
|
|
|
+series. The next `iterator` is only called once the current one has completed.
|
|
|
+The results array will be in the same order as the original.
|
|
|
+
|
|
|
+
|
|
|
+## Utils
|
|
|
+
|
|
|
+<a name="memoize" />
|
|
|
+### memoize(fn, [hasher])
|
|
|
+
|
|
|
+Caches the results of an `async` function. When creating a hash to store function
|
|
|
+results against, the callback is omitted from the hash and an optional hash
|
|
|
+function can be used.
|
|
|
+
|
|
|
+The cache of results is exposed as the `memo` property of the function returned
|
|
|
+by `memoize`.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `fn` - The function to proxy and cache results from.
|
|
|
+* `hasher` - Tn optional function for generating a custom hash for storing
|
|
|
+ results. It has all the arguments applied to it apart from the callback, and
|
|
|
+ must be synchronous.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+var slow_fn = function (name, callback) {
|
|
|
+ // do something
|
|
|
+ callback(null, result);
|
|
|
+};
|
|
|
+var fn = async.memoize(slow_fn);
|
|
|
+
|
|
|
+// fn can now be used as if it were slow_fn
|
|
|
+fn('some name', function () {
|
|
|
+ // callback
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+<a name="unmemoize" />
|
|
|
+### unmemoize(fn)
|
|
|
+
|
|
|
+Undoes a [`memoize`](#memoize)d function, reverting it to the original, unmemoized
|
|
|
+form. Handy for testing.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `fn` - the memoized function
|
|
|
+
|
|
|
+<a name="log" />
|
|
|
+### log(function, arguments)
|
|
|
+
|
|
|
+Logs the result of an `async` function to the `console`. Only works in Node.js or
|
|
|
+in browsers that support `console.log` and `console.error` (such as FF and Chrome).
|
|
|
+If multiple arguments are returned from the async function, `console.log` is
|
|
|
+called on each argument in order.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `function` - The function you want to eventually apply all arguments to.
|
|
|
+* `arguments...` - Any number of arguments to apply to the function.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+var hello = function(name, callback){
|
|
|
+ setTimeout(function(){
|
|
|
+ callback(null, 'hello ' + name);
|
|
|
+ }, 1000);
|
|
|
+};
|
|
|
+```
|
|
|
+```js
|
|
|
+node> async.log(hello, 'world');
|
|
|
+'hello world'
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="dir" />
|
|
|
+### dir(function, arguments)
|
|
|
+
|
|
|
+Logs the result of an `async` function to the `console` using `console.dir` to
|
|
|
+display the properties of the resulting object. Only works in Node.js or
|
|
|
+in browsers that support `console.dir` and `console.error` (such as FF and Chrome).
|
|
|
+If multiple arguments are returned from the async function, `console.dir` is
|
|
|
+called on each argument in order.
|
|
|
+
|
|
|
+__Arguments__
|
|
|
+
|
|
|
+* `function` - The function you want to eventually apply all arguments to.
|
|
|
+* `arguments...` - Any number of arguments to apply to the function.
|
|
|
+
|
|
|
+__Example__
|
|
|
+
|
|
|
+```js
|
|
|
+var hello = function(name, callback){
|
|
|
+ setTimeout(function(){
|
|
|
+ callback(null, {hello: name});
|
|
|
+ }, 1000);
|
|
|
+};
|
|
|
+```
|
|
|
+```js
|
|
|
+node> async.dir(hello, 'world');
|
|
|
+{hello: 'world'}
|
|
|
+```
|
|
|
+
|
|
|
+---------------------------------------
|
|
|
+
|
|
|
+<a name="noConflict" />
|
|
|
+### noConflict()
|
|
|
+
|
|
|
+Changes the value of `async` back to its original value, returning a reference to the
|
|
|
+`async` object.
|