|
5 | 5 | [](https://coveralls.io/r/caolan/async?branch=master)
|
6 | 6 | [](https://gitter.im/caolan/async?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
7 | 7 |
|
8 |
| -*For Async v1.5.x documentation, go [HERE](https://github.com/caolan/async/blob/v1.5.2/README.md)* |
9 |
| - |
10 |
| -Async is a utility module which provides straight-forward, powerful functions |
11 |
| -for working with asynchronous JavaScript. Although originally designed for |
12 |
| -use with [Node.js](https://nodejs.org/) and installable via `npm install --save async`, |
13 |
| -it can also be used directly in the browser. |
14 |
| - |
15 |
| -Async is also installable via: |
16 |
| - |
17 |
| -- [bower](http://bower.io/): `bower install async` |
18 |
| -- [component](https://github.com/componentjs/component): `component install caolan/async` |
19 |
| -- [jam](http://jamjs.org/): `jam install async` |
20 |
| - |
21 |
| -Async provides around 70 functions that include the usual 'functional' |
22 |
| -suspects (`map`, `reduce`, `filter`, `each`…) as well as some common patterns |
23 |
| -for asynchronous control flow (`parallel`, `series`, `waterfall`…). All these |
24 |
| -functions assume you follow the Node.js convention of providing a single |
25 |
| -callback as the last argument of your asynchronous function -- a callback which expects an Error as its first argument -- and calling the callback once. |
26 |
| - |
27 |
| - |
28 |
| -## Quick Examples |
29 |
| - |
30 |
| -```js |
31 |
| -async.map(['file1','file2','file3'], fs.stat, function(err, results){ |
32 |
| - // results is now an array of stats for each file |
33 |
| -}); |
34 |
| - |
35 |
| -async.filter(['file1','file2','file3'], function(filePath, callback) { |
36 |
| - fs.access(filePath, function(err) { |
37 |
| - callback(null, !err) |
38 |
| - }); |
39 |
| -}, function(err, results){ |
40 |
| - // results now equals an array of the existing files |
41 |
| -}); |
42 |
| - |
43 |
| -async.parallel([ |
44 |
| - function(callback){ ... }, |
45 |
| - function(callback){ ... } |
46 |
| -], function(err, results) { |
47 |
| - // optional callback |
48 |
| -}; |
49 |
| - |
50 |
| -async.series([ |
51 |
| - function(callback){ ... }, |
52 |
| - function(callback){ ... } |
53 |
| -]); |
54 |
| -``` |
55 |
| -
|
56 |
| -There are many more functions available so take a look at the docs below for a |
57 |
| -full list. This module aims to be comprehensive, so if you feel anything is |
58 |
| -missing please create a GitHub issue for it. |
59 |
| -
|
60 |
| -## Common Pitfalls [(StackOverflow)](http://stackoverflow.com/questions/tagged/async.js) |
61 |
| -
|
62 |
| -### Synchronous iteration functions |
63 |
| -
|
64 |
| -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. |
65 |
| -
|
66 |
| -This can also arise by accident if you callback early in certain cases: |
67 |
| -
|
68 |
| -```js |
69 |
| -async.eachSeries(hugeArray, function iteratee(item, callback) { |
70 |
| - if (inCache(item)) { |
71 |
| - callback(null, cache[item]); // if many items are cached, you'll overflow |
72 |
| - } else { |
73 |
| - doSomeIO(item, callback); |
74 |
| - } |
75 |
| -}, function done() { |
76 |
| - //... |
77 |
| -}); |
78 |
| -``` |
79 |
| -
|
80 |
| -Just change it to: |
81 |
| -
|
82 |
| -```js |
83 |
| -async.eachSeries(hugeArray, function iteratee(item, callback) { |
84 |
| - if (inCache(item)) { |
85 |
| - async.setImmediate(function () { |
86 |
| - callback(null, cache[item]); |
87 |
| - }); |
88 |
| - } else { |
89 |
| - doSomeIO(item, callback); |
90 |
| - //... |
91 |
| - } |
92 |
| -}); |
93 |
| -``` |
94 |
| -
|
95 |
| -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. |
96 |
| -
|
97 |
| -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. |
98 |
| -
|
99 |
| -
|
100 |
| -### Multiple callbacks |
101 |
| -
|
102 |
| -Make sure to always `return` when calling a callback early, otherwise you will cause multiple callbacks and unpredictable behavior in many cases. |
103 |
| -
|
104 |
| -```js |
105 |
| -async.waterfall([ |
106 |
| - function (callback) { |
107 |
| - getSomething(options, function (err, result) { |
108 |
| - if (err) { |
109 |
| - callback(new Error("failed getting something:" + err.message)); |
110 |
| - // we should return here |
111 |
| - } |
112 |
| - // since we did not return, this callback still will be called and |
113 |
| - // `processData` will be called twice |
114 |
| - callback(null, result); |
115 |
| - }); |
116 |
| - }, |
117 |
| - processData |
118 |
| -], done) |
119 |
| -``` |
120 |
| -
|
121 |
| -It is always good practice to `return callback(err, result)` whenever a callback call is not the last statement of a function. |
| 8 | +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 install --save async`, it can also be used directly in the browser. |
122 | 9 |
|
| 10 | +For Documentation, visit <http://caolan.github.io/async/> |
123 | 11 |
|
124 |
| -### Binding a context to an iteratee |
125 |
| -
|
126 |
| -This section is really about `bind`, not about `async`. If you are wondering how to |
127 |
| -make `async` execute your iteratees in a given context, or are confused as to why |
128 |
| -a method of another library isn't working as an iteratee, study this example: |
129 |
| -
|
130 |
| -```js |
131 |
| -// Here is a simple object with an (unnecessarily roundabout) squaring method |
132 |
| -var AsyncSquaringLibrary = { |
133 |
| - squareExponent: 2, |
134 |
| - square: function(number, callback){ |
135 |
| - var result = Math.pow(number, this.squareExponent); |
136 |
| - setTimeout(function(){ |
137 |
| - callback(null, result); |
138 |
| - }, 200); |
139 |
| - } |
140 |
| -}; |
141 |
| - |
142 |
| -async.map([1, 2, 3], AsyncSquaringLibrary.square, function(err, result){ |
143 |
| - // result is [NaN, NaN, NaN] |
144 |
| - // This fails because the `this.squareExponent` expression in the square |
145 |
| - // function is not evaluated in the context of AsyncSquaringLibrary, and is |
146 |
| - // therefore undefined. |
147 |
| -}); |
148 |
| - |
149 |
| -async.map([1, 2, 3], AsyncSquaringLibrary.square.bind(AsyncSquaringLibrary), function(err, result){ |
150 |
| - // result is [1, 4, 9] |
151 |
| - // With the help of bind we can attach a context to the iteratee before |
152 |
| - // passing it to async. Now the square function will be executed in its |
153 |
| - // 'home' AsyncSquaringLibrary context and the value of `this.squareExponent` |
154 |
| - // will be as expected. |
155 |
| -}); |
156 |
| -``` |
157 |
| -
|
158 |
| -## Download |
159 |
| -
|
160 |
| -The source is available for download from |
161 |
| -[GitHub](https://raw.githubusercontent.com/caolan/async/master/dist/async.min.js). |
162 |
| -Alternatively, you can install using npm: |
163 |
| -
|
164 |
| -```bash |
165 |
| -$ npm install --save async |
166 |
| -``` |
167 |
| -
|
168 |
| -As well as using Bower: |
169 |
| -
|
170 |
| -```bash |
171 |
| -$ bower install async |
172 |
| -``` |
173 |
| -
|
174 |
| -You can then `require()` async as normal: |
175 |
| -
|
176 |
| -```js |
177 |
| -var async = require("async"); |
178 |
| -``` |
179 |
| -
|
180 |
| -Or require individual methods: |
181 |
| -
|
182 |
| -```js |
183 |
| -var waterfall = require("async/waterfall"); |
184 |
| -var map = require("async/map"); |
185 |
| -``` |
186 |
| -
|
187 |
| -__Development:__ [async.js](https://raw.githubusercontent.com/caolan/async/master/dist/async.js) - 29.6kb Uncompressed |
188 |
| -
|
189 |
| -### In the Browser |
190 |
| -
|
191 |
| -Async should work in any ES5 environment (IE9 and above). |
192 |
| -
|
193 |
| -Usage: |
194 |
| -
|
195 |
| -```html |
196 |
| -<script type="text/javascript" src="async.js"></script> |
197 |
| -<script type="text/javascript"> |
198 |
| - |
199 |
| - async.map(data, asyncProcess, function(err, results){ |
200 |
| - alert(results); |
201 |
| - }); |
202 |
| - |
203 |
| -</script> |
204 |
| -``` |
205 |
| -
|
206 |
| -### ES Modules |
207 |
| -
|
208 |
| -We also provide async as a collection of ES2015 modules, in an alternative `async-es` package on npm. |
209 |
| -
|
210 |
| -```bash |
211 |
| -$ npm install --save async-es |
212 |
| -``` |
213 |
| -
|
214 |
| -```js |
215 |
| -import waterfall from 'async-es/waterfall'; |
216 |
| -import async from 'async-es'; |
217 |
| -``` |
218 |
| -
|
| 12 | +*For Async v1.5.x documentation, go [HERE](https://github.com/caolan/async/blob/v1.5.2/README.md)* |
0 commit comments