1 /*global setTimeout: false, console: false */
6 // global on the server, window in the browser
8 previous_async = root.async;
10 if (typeof module !== 'undefined' && module.exports) {
11 module.exports = async;
17 async.noConflict = function () {
18 root.async = previous_async;
22 //// cross-browser compatiblity functions ////
24 var _forEach = function (arr, iterator) {
26 return arr.forEach(iterator);
28 for (var i = 0; i < arr.length; i += 1) {
29 iterator(arr[i], i, arr);
33 var _map = function (arr, iterator) {
35 return arr.map(iterator);
38 _forEach(arr, function (x, i, a) {
39 results.push(iterator(x, i, a));
44 var _reduce = function (arr, iterator, memo) {
46 return arr.reduce(iterator, memo);
48 _forEach(arr, function (x, i, a) {
49 memo = iterator(memo, x, i, a);
54 var _keys = function (obj) {
56 return Object.keys(obj);
60 if (obj.hasOwnProperty(k)) {
67 var _indexOf = function (arr, item) {
69 return arr.indexOf(item);
71 for (var i = 0; i < arr.length; i += 1) {
72 if (arr[i] === item) {
79 //// exported async module functions ////
81 //// nextTick implementation with browser-compatible fallback ////
82 if (typeof process === 'undefined' || !(process.nextTick)) {
83 async.nextTick = function (fn) {
88 async.nextTick = process.nextTick;
91 async.forEach = function (arr, iterator, callback) {
96 _forEach(arr, function (x) {
97 iterator(x, function (err) {
100 callback = function () {};
104 if (completed === arr.length) {
112 async.forEachSeries = function (arr, iterator, callback) {
117 var iterate = function () {
118 iterator(arr[completed], function (err) {
121 callback = function () {};
125 if (completed === arr.length) {
138 var doParallel = function (fn) {
140 var args = Array.prototype.slice.call(arguments);
141 return fn.apply(null, [async.forEach].concat(args));
144 var doSeries = function (fn) {
146 var args = Array.prototype.slice.call(arguments);
147 return fn.apply(null, [async.forEachSeries].concat(args));
152 var _asyncMap = function (eachfn, arr, iterator, callback) {
154 arr = _map(arr, function (x, i) {
155 return {index: i, value: x};
157 eachfn(arr, function (x, callback) {
158 iterator(x.value, function (err, v) {
159 results[x.index] = v;
163 callback(err, results);
166 async.map = doParallel(_asyncMap);
167 async.mapSeries = doSeries(_asyncMap);
170 // reduce only has a series version, as doing reduce in parallel won't
171 // work in many situations.
172 async.reduce = function (arr, memo, iterator, callback) {
173 async.forEachSeries(arr, function (x, callback) {
174 iterator(memo, x, function (err, v) {
183 async.inject = async.reduce;
185 async.foldl = async.reduce;
187 async.reduceRight = function (arr, memo, iterator, callback) {
188 var reversed = _map(arr, function (x) {
191 async.reduce(reversed, memo, iterator, callback);
194 async.foldr = async.reduceRight;
196 var _filter = function (eachfn, arr, iterator, callback) {
198 arr = _map(arr, function (x, i) {
199 return {index: i, value: x};
201 eachfn(arr, function (x, callback) {
202 iterator(x.value, function (v) {
209 callback(_map(results.sort(function (a, b) {
210 return a.index - b.index;
216 async.filter = doParallel(_filter);
217 async.filterSeries = doSeries(_filter);
219 async.select = async.filter;
220 async.selectSeries = async.filterSeries;
222 var _reject = function (eachfn, arr, iterator, callback) {
224 arr = _map(arr, function (x, i) {
225 return {index: i, value: x};
227 eachfn(arr, function (x, callback) {
228 iterator(x.value, function (v) {
235 callback(_map(results.sort(function (a, b) {
236 return a.index - b.index;
242 async.reject = doParallel(_reject);
243 async.rejectSeries = doSeries(_reject);
245 var _detect = function (eachfn, arr, iterator, main_callback) {
246 eachfn(arr, function (x, callback) {
247 iterator(x, function (result) {
259 async.detect = doParallel(_detect);
260 async.detectSeries = doSeries(_detect);
262 async.some = function (arr, iterator, main_callback) {
263 async.forEach(arr, function (x, callback) {
264 iterator(x, function (v) {
267 main_callback = function () {};
272 main_callback(false);
276 async.any = async.some;
278 async.every = function (arr, iterator, main_callback) {
279 async.forEach(arr, function (x, callback) {
280 iterator(x, function (v) {
282 main_callback(false);
283 main_callback = function () {};
292 async.all = async.every;
294 async.sortBy = function (arr, iterator, callback) {
295 async.map(arr, function (x, callback) {
296 iterator(x, function (err, criteria) {
301 callback(null, {value: x, criteria: criteria});
304 }, function (err, results) {
306 return callback(err);
309 var fn = function (left, right) {
310 var a = left.criteria, b = right.criteria;
311 return a < b ? -1 : a > b ? 1 : 0;
313 callback(null, _map(results.sort(fn), function (x) {
320 async.auto = function (tasks, callback) {
321 callback = callback || function () {};
322 var keys = _keys(tasks);
324 return callback(null);
330 var addListener = function (fn) {
331 listeners.unshift(fn);
333 var removeListener = function (fn) {
334 for (var i = 0; i < listeners.length; i += 1) {
335 if (listeners[i] === fn) {
336 listeners.splice(i, 1);
341 var taskComplete = function () {
342 _forEach(listeners, function (fn) {
347 addListener(function () {
348 if (completed.length === keys.length) {
353 _forEach(keys, function (k) {
354 var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k];
355 var taskCallback = function (err) {
358 // stop subsequent errors hitting callback multiple times
359 callback = function () {};
366 var requires = task.slice(0, Math.abs(task.length - 1)) || [];
367 var ready = function () {
368 return _reduce(requires, function (a, x) {
369 return (a && _indexOf(completed, x) !== -1);
373 task[task.length - 1](taskCallback);
376 var listener = function () {
378 removeListener(listener);
379 task[task.length - 1](taskCallback);
382 addListener(listener);
387 async.waterfall = function (tasks, callback) {
391 callback = callback || function () {};
392 var wrapIterator = function (iterator) {
393 return function (err) {
396 callback = function () {};
399 var args = Array.prototype.slice.call(arguments, 1);
400 var next = iterator.next();
402 args.push(wrapIterator(next));
407 async.nextTick(function () {
408 iterator.apply(null, args);
413 wrapIterator(async.iterator(tasks))();
416 async.parallel = function (tasks, callback) {
417 callback = callback || function () {};
418 if (tasks.constructor === Array) {
419 async.map(tasks, function (fn, callback) {
422 var args = Array.prototype.slice.call(arguments, 1);
423 if (args.length <= 1) {
426 callback.call(null, err, args);
433 async.forEach(_keys(tasks), function (k, callback) {
434 tasks[k](function (err) {
435 var args = Array.prototype.slice.call(arguments, 1);
436 if (args.length <= 1) {
443 callback(err, results);
448 async.series = function (tasks, callback) {
449 callback = callback || function () {};
450 if (tasks.constructor === Array) {
451 async.mapSeries(tasks, function (fn, callback) {
454 var args = Array.prototype.slice.call(arguments, 1);
455 if (args.length <= 1) {
458 callback.call(null, err, args);
465 async.forEachSeries(_keys(tasks), function (k, callback) {
466 tasks[k](function (err) {
467 var args = Array.prototype.slice.call(arguments, 1);
468 if (args.length <= 1) {
475 callback(err, results);
480 async.iterator = function (tasks) {
481 var makeCallback = function (index) {
482 var fn = function () {
484 tasks[index].apply(null, arguments);
488 fn.next = function () {
489 return (index < tasks.length - 1) ? makeCallback(index + 1): null;
493 return makeCallback(0);
496 async.apply = function (fn) {
497 var args = Array.prototype.slice.call(arguments, 1);
500 null, args.concat(Array.prototype.slice.call(arguments))
505 var _concat = function (eachfn, arr, fn, callback) {
507 eachfn(arr, function (x, cb) {
508 fn(x, function (err, y) {
509 r = r.concat(y || []);
516 async.concat = doParallel(_concat);
517 async.concatSeries = doSeries(_concat);
519 async.whilst = function (test, iterator, callback) {
521 iterator(function (err) {
523 return callback(err);
525 async.whilst(test, iterator, callback);
533 async.until = function (test, iterator, callback) {
535 iterator(function (err) {
537 return callback(err);
539 async.until(test, iterator, callback);
547 async.queue = function (worker, concurrency) {
551 concurrency: concurrency,
555 push: function (data, callback) {
556 tasks.push({data: data, callback: callback});
557 if(q.saturated && tasks.length == concurrency) q.saturated();
558 async.nextTick(q.process);
560 process: function () {
561 if (workers < q.concurrency && tasks.length) {
562 var task = tasks.splice(0, 1)[0];
563 if(q.empty && tasks.length == 0) q.empty();
565 worker(task.data, function () {
568 task.callback.apply(task, arguments);
570 if(q.drain && tasks.length + workers == 0) q.drain();
575 length: function () {
578 running: function () {
585 var _console_fn = function (name) {
586 return function (fn) {
587 var args = Array.prototype.slice.call(arguments, 1);
588 fn.apply(null, args.concat([function (err) {
589 var args = Array.prototype.slice.call(arguments, 1);
590 if (typeof console !== 'undefined') {
596 else if (console[name]) {
597 _forEach(args, function (x) {
605 async.log = _console_fn('log');
606 async.dir = _console_fn('dir');
607 /*async.info = _console_fn('info');
608 async.warn = _console_fn('warn');
609 async.error = _console_fn('error');*/
611 async.memoize = function (fn, hasher) {
613 hasher = hasher || function (x) {
617 var args = Array.prototype.slice.call(arguments);
618 var callback = args.pop();
619 var key = hasher.apply(null, args);
621 callback.apply(null, memo[key]);
624 fn.apply(null, args.concat([function () {
625 memo[key] = arguments;
626 callback.apply(null, arguments);