UNPKG

15.1 kBJavaScriptView Raw
1(function(){
2
3 var async = {};
4
5 // global on the server, window in the browser
6 var root = this;
7 var previous_async = root.async;
8
9 if(typeof module !== 'undefined' && module.exports) module.exports = async;
10 else root.async = async;
11
12 async.noConflict = function(){
13 root.async = previous_async;
14 return async;
15 };
16
17 //// cross-browser compatiblity functions ////
18
19 var _forEach = function(arr, iterator){
20 if(arr.forEach) return arr.forEach(iterator);
21 for(var i=0; i<arr.length; i++){
22 iterator(arr[i], i, arr);
23 }
24 };
25
26 var _map = function(arr, iterator){
27 if(arr.map) return arr.map(iterator);
28 var results = [];
29 _forEach(arr, function(x, i, a){
30 results.push(iterator(x, i, a));
31 })
32 return results;
33 };
34
35 var _reduce = function(arr, iterator, memo){
36 if(arr.reduce) return arr.reduce(iterator, memo);
37 _forEach(arr, function(x, i, a){
38 memo = iterator(memo, x, i, a);
39 });
40 return memo;
41 };
42
43 var _keys = function(obj){
44 if(Object.keys) return Object.keys(obj);
45 var keys = [];
46 for(var k in obj){
47 if(obj.hasOwnProperty(k)) keys.push(k);
48 }
49 return keys;
50 };
51
52 var _indexOf = function(arr, item){
53 if(arr.indexOf) return arr.indexOf(item);
54 for(var i=0; i<arr.length; i++){
55 if(arr[i] === item) return i;
56 }
57 return -1;
58 };
59
60 //// exported async module functions ////
61
62 //// nextTick implementation with browser-compatible fallback ////
63 async.nextTick = function(fn){
64 if(typeof process == 'undefined' || !(process.nextTick)){
65 setTimeout(fn, 0);
66 }
67 else process.nextTick(fn);
68 };
69
70 async.forEach = function(arr, iterator, callback){
71 if(!arr.length) return callback();
72 var completed = 0;
73 _forEach(arr, function(x){
74 iterator(x, function(err){
75 if(err){
76 callback(err);
77 callback = function(){};
78 }
79 else {
80 completed++;
81 if(completed == arr.length) callback();
82 }
83 });
84 });
85 };
86
87 async.forEachSeries = function(arr, iterator, callback){
88 if(!arr.length) return callback();
89 var completed = 0;
90 var iterate = function(){
91 iterator(arr[completed], function(err){
92 if(err){
93 callback(err);
94 callback = function(){};
95 }
96 else {
97 completed++;
98 if(completed == arr.length) callback();
99 else iterate();
100 }
101 });
102 };
103 iterate();
104 };
105
106
107 var doParallel = function(fn){
108 return function(){
109 var args = Array.prototype.slice.call(arguments);
110 return fn.apply(null, [async.forEach].concat(args));
111 };
112 };
113 var doSeries = function(fn){
114 return function(){
115 var args = Array.prototype.slice.call(arguments);
116 return fn.apply(null, [async.forEachSeries].concat(args));
117 };
118 };
119
120
121 var _asyncMap = function(eachfn, arr, iterator, callback){
122 var results = [];
123 arr = _map(arr, function(x, i){
124 return {index: i, value: x};
125 });
126 eachfn(arr, function(x, callback){
127 iterator(x.value, function(err, v){
128 results[x.index] = v;
129 callback(err);
130 });
131 }, function(err){
132 callback(err, results);
133 });
134 };
135 async.map = doParallel(_asyncMap);
136 async.mapSeries = doSeries(_asyncMap);
137
138
139 // reduce only has a series version, as doing reduce in parallel won't
140 // work in many situations.
141 async.reduce = function(arr, memo, iterator, callback){
142 async.forEachSeries(arr, function(x, callback){
143 iterator(memo, x, function(err, v){
144 memo = v;
145 callback(err);
146 });
147 }, function(err){
148 callback(err, memo);
149 });
150 };
151 // inject alias
152 async.inject = async.reduce;
153 // foldl alias
154 async.foldl = async.reduce;
155
156 async.reduceRight = function(arr, memo, iterator, callback){
157 var reversed = _map(arr, function(x){return x;}).reverse();
158 async.reduce(reversed, memo, iterator, callback);
159 };
160 // foldr alias
161 async.foldr = async.reduceRight;
162
163 var _filter = function(eachfn, arr, iterator, callback){
164 var results = [];
165 arr = _map(arr, function(x, i){
166 return {index: i, value: x};
167 });
168 eachfn(arr, function(x, callback){
169 iterator(x.value, function(v){
170 if(v) results.push(x);
171 callback();
172 });
173 }, function(err){
174 callback(_map(results.sort(function(a,b){
175 return a.index - b.index;
176 }), function(x){
177 return x.value;
178 }));
179 });
180 };
181 async.filter = doParallel(_filter);
182 async.filterSeries = doSeries(_filter);
183 // select alias
184 async.select = async.filter;
185 async.selectSeries = async.filterSeries;
186
187 var _reject = function(eachfn, arr, iterator, callback){
188 var results = [];
189 arr = _map(arr, function(x, i){
190 return {index: i, value: x};
191 });
192 eachfn(arr, function(x, callback){
193 iterator(x.value, function(v){
194 if(!v) results.push(x);
195 callback();
196 });
197 }, function(err){
198 callback(_map(results.sort(function(a,b){
199 return a.index - b.index;
200 }), function(x){
201 return x.value;
202 }));
203 });
204 };
205 async.reject = doParallel(_reject);
206 async.rejectSeries = doSeries(_reject);
207
208 var _detect = function(eachfn, arr, iterator, main_callback){
209 eachfn(arr, function(x, callback){
210 iterator(x, function(result){
211 if(result) main_callback(x);
212 else callback();
213 });
214 }, function(err){
215 main_callback();
216 });
217 };
218 async.detect = doParallel(_detect);
219 async.detectSeries = doSeries(_detect);
220
221 async.some = function(arr, iterator, main_callback){
222 async.forEach(arr, function(x, callback){
223 iterator(x, function(v){
224 if(v){
225 main_callback(true);
226 main_callback = function(){};
227 }
228 callback();
229 });
230 }, function(err){
231 main_callback(false);
232 });
233 };
234 // any alias
235 async.any = async.some;
236
237 async.every = function(arr, iterator, main_callback){
238 async.forEach(arr, function(x, callback){
239 iterator(x, function(v){
240 if(!v){
241 main_callback(false);
242 main_callback = function(){};
243 }
244 callback();
245 });
246 }, function(err){
247 main_callback(true);
248 });
249 };
250 // all alias
251 async.all = async.every;
252
253 async.sortBy = function(arr, iterator, callback){
254 async.map(arr, function(x, callback){
255 iterator(x, function(err, criteria){
256 if(err) callback(err);
257 else callback(null, {value: x, criteria: criteria});
258 });
259 }, function(err, results){
260 if(err) return callback(err);
261 else callback(null, _map(results.sort(function(left, right){
262 var a = left.criteria, b = right.criteria;
263 return a < b ? -1 : a > b ? 1 : 0;
264 }), function(x){return x.value;}));
265 })
266 };
267
268 async.auto = function(tasks, callback){
269 callback = callback || function(){};
270 var keys = _keys(tasks);
271 if(!keys.length) return callback(null);
272
273 var completed = [];
274
275 var listeners = [];
276 var addListener = function(fn){
277 listeners.unshift(fn);
278 };
279 var removeListener = function(fn){
280 for(var i=0; i<listeners.length; i++){
281 if(listeners[i] === fn){
282 listeners.splice(i, 1);
283 return;
284 }
285 }
286 };
287 var taskComplete = function(){
288 _forEach(listeners, function(fn){fn();});
289 };
290
291 addListener(function(){
292 if(completed.length == keys.length){
293 callback(null);
294 }
295 });
296
297 _forEach(keys, function(k){
298 var task = (tasks[k] instanceof Function)? [tasks[k]]: tasks[k];
299 var taskCallback = function(err){
300 if(err){
301 callback(err);
302 // stop subsequent errors hitting callback multiple times
303 callback = function(){};
304 }
305 else {
306 completed.push(k);
307 taskComplete();
308 }
309 };
310 var requires = task.slice(0, Math.abs(task.length-1)) || [];
311 var ready = function(){
312 return _reduce(requires, function(a,x){
313 return (a && _indexOf(completed, x) != -1);
314 }, true);
315 };
316 if(ready()) task[task.length-1](taskCallback);
317 else {
318 var listener = function(){
319 if(ready()){
320 removeListener(listener);
321 task[task.length-1](taskCallback);
322 }
323 };
324 addListener(listener);
325 }
326 });
327 };
328
329 async.waterfall = function(tasks, callback){
330 if(!tasks.length) return callback();
331 callback = callback || function(){};
332 var wrapIterator = function(iterator){
333 return function(err){
334 if(err){
335 callback(err);
336 callback = function(){};
337 }
338 else {
339 var args = Array.prototype.slice.call(arguments, 1);
340 var next = iterator.next();
341 if(next) args.push(wrapIterator(next));
342 else args.push(callback);
343 async.nextTick(function(){iterator.apply(null, args);});
344 }
345 };
346 };
347 wrapIterator(async.iterator(tasks))();
348 };
349
350 async.parallel = function(tasks, callback){
351 callback = callback || function(){};
352 if (tasks.constructor === Array) {
353 async.map(tasks, function(fn, callback){
354 if(fn){
355 fn(function(err){
356 var args = Array.prototype.slice.call(arguments,1);
357 if(args.length <= 1) args = args[0];
358 callback.call(null, err, args || null);
359 });
360 }
361 }, callback);
362 }
363 else {
364 var results = {};
365 async.forEach(_keys(tasks), function (k, callback) {
366 tasks[k](function (err) {
367 var args = Array.prototype.slice.call(arguments,1);
368 if(args.length <= 1) args = args[0];
369 results[k] = args;
370 callback(err);
371 });
372 }, function (err) {
373 callback(err, results);
374 });
375 }
376 };
377
378 async.series = function(tasks, callback){
379 callback = callback || function(){};
380 if (tasks.constructor === Array) {
381 async.mapSeries(tasks, function(fn, callback){
382 if(fn){
383 fn(function(err){
384 var args = Array.prototype.slice.call(arguments,1);
385 if(args.length <= 1) args = args[0];
386 callback.call(null, err, args || null);
387 });
388 }
389 }, callback);
390 }
391 else {
392 var results = {};
393 async.forEachSeries(_keys(tasks), function (k, callback) {
394 tasks[k](function (err) {
395 var args = Array.prototype.slice.call(arguments,1);
396 if(args.length <= 1) args = args[0];
397 results[k] = args;
398 callback(err);
399 });
400 }, function (err) {
401 callback(err, results);
402 });
403 }
404 };
405
406 async.iterator = function(tasks){
407 var makeCallback = function(index){
408 var fn = function(){
409 if(tasks.length) tasks[index].apply(null, arguments);
410 return fn.next();
411 };
412 fn.next = function(){
413 return (index < tasks.length-1)? makeCallback(index+1): null;
414 };
415 return fn;
416 };
417 return makeCallback(0);
418 };
419
420 async.apply = function(fn){
421 var args = Array.prototype.slice.call(arguments, 1);
422 return function(){
423 return fn.apply(
424 null, args.concat(Array.prototype.slice.call(arguments))
425 );
426 };
427 };
428
429 var _concat = function(eachfn, arr, fn, callback){
430 var r = [];
431 eachfn(arr, function(x, cb){
432 fn(x, function(err, y){
433 r = r.concat(y || []);
434 cb(err);
435 });
436 }, function(err){
437 callback(err, r);
438 });
439 };
440 async.concat = doParallel(_concat);
441 async.concatSeries = doSeries(_concat);
442
443 async.whilst = function(test, iterator, callback){
444 if (test()) {
445 iterator(function (err) {
446 if (err) return callback(err);
447 async.whilst(test, iterator, callback);
448 });
449 }
450 else callback();
451 };
452
453 async.until = function(test, iterator, callback){
454 if (!test()) {
455 iterator(function (err) {
456 if (err) return callback(err);
457 async.until(test, iterator, callback);
458 });
459 }
460 else callback();
461 };
462
463 var _console_fn = function(name){
464 return function(fn){
465 var args = Array.prototype.slice.call(arguments, 1);
466 fn.apply(null, args.concat([function(err){
467 var args = Array.prototype.slice.call(arguments, 1);
468 if(typeof console != 'undefined'){
469 if(err){
470 if(console.error) console.error(err);
471 }
472 else if(console[name]){
473 _forEach(args, function(x){console[name](x);});
474 }
475 }
476 }]));
477 };
478 };
479 async.log = _console_fn('log');
480 async.dir = _console_fn('dir');
481 /*async.info = _console_fn('info');
482 async.warn = _console_fn('warn');
483 async.error = _console_fn('error');*/
484
485})();