UNPKG

38.6 kBJavaScriptView Raw
1/*!
2 * async
3 * https://github.com/caolan/async
4 *
5 * Copyright 2010-2014 Caolan McMahon
6 * Released under the MIT license
7 */
8(function () {
9
10 var async = {};
11 function noop() {}
12 function identity(v) {
13 return v;
14 }
15 function toBool(v) {
16 return !!v;
17 }
18 function notId(v) {
19 return !v;
20 }
21
22 // global on the server, window in the browser
23 var previous_async;
24
25 // Establish the root object, `window` (`self`) in the browser, `global`
26 // on the server, or `this` in some virtual machines. We use `self`
27 // instead of `window` for `WebWorker` support.
28 var root = typeof self === 'object' && self.self === self && self ||
29 typeof global === 'object' && global.global === global && global ||
30 this;
31
32 if (root != null) {
33 previous_async = root.async;
34 }
35
36 async.noConflict = function () {
37 root.async = previous_async;
38 return async;
39 };
40
41 function only_once(fn) {
42 return function() {
43 if (fn === null) throw new Error("Callback was already called.");
44 fn.apply(this, arguments);
45 fn = null;
46 };
47 }
48
49 function _once(fn) {
50 return function() {
51 if (fn === null) return;
52 fn.apply(this, arguments);
53 fn = null;
54 };
55 }
56
57 //// cross-browser compatiblity functions ////
58
59 var _toString = Object.prototype.toString;
60
61 var _isArray = Array.isArray || function (obj) {
62 return _toString.call(obj) === '[object Array]';
63 };
64
65 // Ported from underscore.js isObject
66 var _isObject = function(obj) {
67 var type = typeof obj;
68 return type === 'function' || type === 'object' && !!obj;
69 };
70
71 function _isArrayLike(arr) {
72 return _isArray(arr) || (
73 // has a positive integer length property
74 typeof arr.length === "number" &&
75 arr.length >= 0 &&
76 arr.length % 1 === 0
77 );
78 }
79
80 function _arrayEach(arr, iterator) {
81 var index = -1,
82 length = arr.length;
83
84 while (++index < length) {
85 iterator(arr[index], index, arr);
86 }
87 }
88
89 function _map(arr, iterator) {
90 var index = -1,
91 length = arr.length,
92 result = Array(length);
93
94 while (++index < length) {
95 result[index] = iterator(arr[index], index, arr);
96 }
97 return result;
98 }
99
100 function _range(count) {
101 return _map(Array(count), function (v, i) { return i; });
102 }
103
104 function _reduce(arr, iterator, memo) {
105 _arrayEach(arr, function (x, i, a) {
106 memo = iterator(memo, x, i, a);
107 });
108 return memo;
109 }
110
111 function _forEachOf(object, iterator) {
112 _arrayEach(_keys(object), function (key) {
113 iterator(object[key], key);
114 });
115 }
116
117 function _indexOf(arr, item) {
118 for (var i = 0; i < arr.length; i++) {
119 if (arr[i] === item) return i;
120 }
121 return -1;
122 }
123
124 var _keys = Object.keys || function (obj) {
125 var keys = [];
126 for (var k in obj) {
127 if (obj.hasOwnProperty(k)) {
128 keys.push(k);
129 }
130 }
131 return keys;
132 };
133
134 function _keyIterator(coll) {
135 var i = -1;
136 var len;
137 var keys;
138 if (_isArrayLike(coll)) {
139 len = coll.length;
140 return function next() {
141 i++;
142 return i < len ? i : null;
143 };
144 } else {
145 keys = _keys(coll);
146 len = keys.length;
147 return function next() {
148 i++;
149 return i < len ? keys[i] : null;
150 };
151 }
152 }
153
154 // Similar to ES6's rest param (http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html)
155 // This accumulates the arguments passed into an array, after a given index.
156 // From underscore.js (https://github.com/jashkenas/underscore/pull/2140).
157 function _restParam(func, startIndex) {
158 startIndex = startIndex == null ? func.length - 1 : +startIndex;
159 return function() {
160 var length = Math.max(arguments.length - startIndex, 0);
161 var rest = Array(length);
162 for (var index = 0; index < length; index++) {
163 rest[index] = arguments[index + startIndex];
164 }
165 switch (startIndex) {
166 case 0: return func.call(this, rest);
167 case 1: return func.call(this, arguments[0], rest);
168 }
169 // Currently unused but handle cases outside of the switch statement:
170 // var args = Array(startIndex + 1);
171 // for (index = 0; index < startIndex; index++) {
172 // args[index] = arguments[index];
173 // }
174 // args[startIndex] = rest;
175 // return func.apply(this, args);
176 };
177 }
178
179 function _withoutIndex(iterator) {
180 return function (value, index, callback) {
181 return iterator(value, callback);
182 };
183 }
184
185 //// exported async module functions ////
186
187 //// nextTick implementation with browser-compatible fallback ////
188
189 // capture the global reference to guard against fakeTimer mocks
190 var _setImmediate = typeof setImmediate === 'function' && setImmediate;
191
192 var _delay = _setImmediate ? function(fn) {
193 // not a direct alias for IE10 compatibility
194 _setImmediate(fn);
195 } : function(fn) {
196 setTimeout(fn, 0);
197 };
198
199 if (typeof process === 'object' && typeof process.nextTick === 'function') {
200 async.nextTick = process.nextTick;
201 } else {
202 async.nextTick = _delay;
203 }
204 async.setImmediate = _setImmediate ? _delay : async.nextTick;
205
206
207 async.forEach =
208 async.each = function (arr, iterator, callback) {
209 return async.eachOf(arr, _withoutIndex(iterator), callback);
210 };
211
212 async.forEachSeries =
213 async.eachSeries = function (arr, iterator, callback) {
214 return async.eachOfSeries(arr, _withoutIndex(iterator), callback);
215 };
216
217
218 async.forEachLimit =
219 async.eachLimit = function (arr, limit, iterator, callback) {
220 return _eachOfLimit(limit)(arr, _withoutIndex(iterator), callback);
221 };
222
223 async.forEachOf =
224 async.eachOf = function (object, iterator, callback) {
225 callback = _once(callback || noop);
226 object = object || [];
227
228 var iter = _keyIterator(object);
229 var key, completed = 0;
230
231 while ((key = iter()) != null) {
232 completed += 1;
233 iterator(object[key], key, only_once(done));
234 }
235
236 if (completed === 0) callback(null);
237
238 function done(err) {
239 completed--;
240 if (err) {
241 callback(err);
242 }
243 // Check key is null in case iterator isn't exhausted
244 // and done resolved synchronously.
245 else if (key === null && completed <= 0) {
246 callback(null);
247 }
248 }
249 };
250
251 async.forEachOfSeries =
252 async.eachOfSeries = function (obj, iterator, callback) {
253 callback = _once(callback || noop);
254 obj = obj || [];
255 var nextKey = _keyIterator(obj);
256 var key = nextKey();
257 function iterate() {
258 var sync = true;
259 if (key === null) {
260 return callback(null);
261 }
262 iterator(obj[key], key, only_once(function (err) {
263 if (err) {
264 callback(err);
265 }
266 else {
267 key = nextKey();
268 if (key === null) {
269 return callback(null);
270 } else {
271 if (sync) {
272 async.setImmediate(iterate);
273 } else {
274 iterate();
275 }
276 }
277 }
278 }));
279 sync = false;
280 }
281 iterate();
282 };
283
284
285
286 async.forEachOfLimit =
287 async.eachOfLimit = function (obj, limit, iterator, callback) {
288 _eachOfLimit(limit)(obj, iterator, callback);
289 };
290
291 function _eachOfLimit(limit) {
292
293 return function (obj, iterator, callback) {
294 callback = _once(callback || noop);
295 obj = obj || [];
296 var nextKey = _keyIterator(obj);
297 if (limit <= 0) {
298 return callback(null);
299 }
300 var done = false;
301 var running = 0;
302 var errored = false;
303
304 (function replenish () {
305 if (done && running <= 0) {
306 return callback(null);
307 }
308
309 while (running < limit && !errored) {
310 var key = nextKey();
311 if (key === null) {
312 done = true;
313 if (running <= 0) {
314 callback(null);
315 }
316 return;
317 }
318 running += 1;
319 iterator(obj[key], key, only_once(function (err) {
320 running -= 1;
321 if (err) {
322 callback(err);
323 errored = true;
324 }
325 else {
326 replenish();
327 }
328 }));
329 }
330 })();
331 };
332 }
333
334
335 function doParallel(fn) {
336 return function (obj, iterator, callback) {
337 return fn(async.eachOf, obj, iterator, callback);
338 };
339 }
340 function doParallelLimit(fn) {
341 return function (obj, limit, iterator, callback) {
342 return fn(_eachOfLimit(limit), obj, iterator, callback);
343 };
344 }
345 function doSeries(fn) {
346 return function (obj, iterator, callback) {
347 return fn(async.eachOfSeries, obj, iterator, callback);
348 };
349 }
350
351 function _asyncMap(eachfn, arr, iterator, callback) {
352 callback = _once(callback || noop);
353 arr = arr || [];
354 var results = _isArrayLike(arr) ? [] : {};
355 eachfn(arr, function (value, index, callback) {
356 iterator(value, function (err, v) {
357 results[index] = v;
358 callback(err);
359 });
360 }, function (err) {
361 callback(err, results);
362 });
363 }
364
365 async.map = doParallel(_asyncMap);
366 async.mapSeries = doSeries(_asyncMap);
367 async.mapLimit = doParallelLimit(_asyncMap);
368
369 // reduce only has a series version, as doing reduce in parallel won't
370 // work in many situations.
371 async.inject =
372 async.foldl =
373 async.reduce = function (arr, memo, iterator, callback) {
374 async.eachOfSeries(arr, function (x, i, callback) {
375 iterator(memo, x, function (err, v) {
376 memo = v;
377 callback(err);
378 });
379 }, function (err) {
380 callback(err, memo);
381 });
382 };
383
384 async.foldr =
385 async.reduceRight = function (arr, memo, iterator, callback) {
386 var reversed = _map(arr, identity).reverse();
387 async.reduce(reversed, memo, iterator, callback);
388 };
389
390 async.transform = function (arr, memo, iterator, callback) {
391 if (arguments.length === 3) {
392 callback = iterator;
393 iterator = memo;
394 memo = _isArray(arr) ? [] : {};
395 }
396
397 async.eachOf(arr, function(v, k, cb) {
398 iterator(memo, v, k, cb);
399 }, function(err) {
400 callback(err, memo);
401 });
402 };
403
404 function _filter(eachfn, arr, iterator, callback) {
405 var results = [];
406 eachfn(arr, function (x, index, callback) {
407 iterator(x, function (v) {
408 if (v) {
409 results.push({index: index, value: x});
410 }
411 callback();
412 });
413 }, function () {
414 callback(_map(results.sort(function (a, b) {
415 return a.index - b.index;
416 }), function (x) {
417 return x.value;
418 }));
419 });
420 }
421
422 async.select =
423 async.filter = doParallel(_filter);
424
425 async.selectLimit =
426 async.filterLimit = doParallelLimit(_filter);
427
428 async.selectSeries =
429 async.filterSeries = doSeries(_filter);
430
431 function _reject(eachfn, arr, iterator, callback) {
432 _filter(eachfn, arr, function(value, cb) {
433 iterator(value, function(v) {
434 cb(!v);
435 });
436 }, callback);
437 }
438 async.reject = doParallel(_reject);
439 async.rejectLimit = doParallelLimit(_reject);
440 async.rejectSeries = doSeries(_reject);
441
442 function _createTester(eachfn, check, getResult) {
443 return function(arr, limit, iterator, cb) {
444 function done() {
445 if (cb) cb(getResult(false, void 0));
446 }
447 function iteratee(x, _, callback) {
448 if (!cb) return callback();
449 iterator(x, function (v) {
450 if (cb && check(v)) {
451 cb(getResult(true, x));
452 cb = iterator = false;
453 }
454 callback();
455 });
456 }
457 if (arguments.length > 3) {
458 eachfn(arr, limit, iteratee, done);
459 } else {
460 cb = iterator;
461 iterator = limit;
462 eachfn(arr, iteratee, done);
463 }
464 };
465 }
466
467 async.any =
468 async.some = _createTester(async.eachOf, toBool, identity);
469
470 async.someLimit = _createTester(async.eachOfLimit, toBool, identity);
471
472 async.all =
473 async.every = _createTester(async.eachOf, notId, notId);
474
475 async.everyLimit = _createTester(async.eachOfLimit, notId, notId);
476
477 function _findGetResult(v, x) {
478 return x;
479 }
480 async.detect = _createTester(async.eachOf, identity, _findGetResult);
481 async.detectSeries = _createTester(async.eachOfSeries, identity, _findGetResult);
482 async.detectLimit = _createTester(async.eachOfLimit, identity, _findGetResult);
483
484 async.sortBy = function (arr, iterator, callback) {
485 async.map(arr, function (x, callback) {
486 iterator(x, function (err, criteria) {
487 if (err) {
488 callback(err);
489 }
490 else {
491 callback(null, {value: x, criteria: criteria});
492 }
493 });
494 }, function (err, results) {
495 if (err) {
496 return callback(err);
497 }
498 else {
499 callback(null, _map(results.sort(comparator), function (x) {
500 return x.value;
501 }));
502 }
503
504 });
505
506 function comparator(left, right) {
507 var a = left.criteria, b = right.criteria;
508 return a < b ? -1 : a > b ? 1 : 0;
509 }
510 };
511
512 async.auto = function (tasks, concurrency, callback) {
513 if (typeof arguments[1] === 'function') {
514 // concurrency is optional, shift the args.
515 callback = concurrency;
516 concurrency = null;
517 }
518 callback = _once(callback || noop);
519 var keys = _keys(tasks);
520 var remainingTasks = keys.length;
521 if (!remainingTasks) {
522 return callback(null);
523 }
524 if (!concurrency) {
525 concurrency = remainingTasks;
526 }
527
528 var results = {};
529 var runningTasks = 0;
530
531 var hasError = false;
532
533 var listeners = [];
534 function addListener(fn) {
535 listeners.unshift(fn);
536 }
537 function removeListener(fn) {
538 var idx = _indexOf(listeners, fn);
539 if (idx >= 0) listeners.splice(idx, 1);
540 }
541 function taskComplete() {
542 remainingTasks--;
543 _arrayEach(listeners.slice(0), function (fn) {
544 fn();
545 });
546 }
547
548 addListener(function () {
549 if (!remainingTasks) {
550 callback(null, results);
551 }
552 });
553
554 _arrayEach(keys, function (k) {
555 if (hasError) return;
556 var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
557 var taskCallback = _restParam(function(err, args) {
558 runningTasks--;
559 if (args.length <= 1) {
560 args = args[0];
561 }
562 if (err) {
563 var safeResults = {};
564 _forEachOf(results, function(val, rkey) {
565 safeResults[rkey] = val;
566 });
567 safeResults[k] = args;
568 hasError = true;
569
570 callback(err, safeResults);
571 }
572 else {
573 results[k] = args;
574 async.setImmediate(taskComplete);
575 }
576 });
577 var requires = task.slice(0, task.length - 1);
578 // prevent dead-locks
579 var len = requires.length;
580 var dep;
581 while (len--) {
582 if (!(dep = tasks[requires[len]])) {
583 throw new Error('Has nonexistent dependency in ' + requires.join(', '));
584 }
585 if (_isArray(dep) && _indexOf(dep, k) >= 0) {
586 throw new Error('Has cyclic dependencies');
587 }
588 }
589 function ready() {
590 return runningTasks < concurrency && _reduce(requires, function (a, x) {
591 return (a && results.hasOwnProperty(x));
592 }, true) && !results.hasOwnProperty(k);
593 }
594 if (ready()) {
595 runningTasks++;
596 task[task.length - 1](taskCallback, results);
597 }
598 else {
599 addListener(listener);
600 }
601 function listener() {
602 if (ready()) {
603 runningTasks++;
604 removeListener(listener);
605 task[task.length - 1](taskCallback, results);
606 }
607 }
608 });
609 };
610
611
612
613 async.retry = function(times, task, callback) {
614 var DEFAULT_TIMES = 5;
615 var DEFAULT_INTERVAL = 0;
616
617 var attempts = [];
618
619 var opts = {
620 times: DEFAULT_TIMES,
621 interval: DEFAULT_INTERVAL
622 };
623
624 function parseTimes(acc, t){
625 if(typeof t === 'number'){
626 acc.times = parseInt(t, 10) || DEFAULT_TIMES;
627 } else if(typeof t === 'object'){
628 acc.times = parseInt(t.times, 10) || DEFAULT_TIMES;
629 acc.interval = parseInt(t.interval, 10) || DEFAULT_INTERVAL;
630 } else {
631 throw new Error('Unsupported argument type for \'times\': ' + typeof t);
632 }
633 }
634
635 var length = arguments.length;
636 if (length < 1 || length > 3) {
637 throw new Error('Invalid arguments - must be either (task), (task, callback), (times, task) or (times, task, callback)');
638 } else if (length <= 2 && typeof times === 'function') {
639 callback = task;
640 task = times;
641 }
642 if (typeof times !== 'function') {
643 parseTimes(opts, times);
644 }
645 opts.callback = callback;
646 opts.task = task;
647
648 function wrappedTask(wrappedCallback, wrappedResults) {
649 function retryAttempt(task, finalAttempt) {
650 return function(seriesCallback) {
651 task(function(err, result){
652 seriesCallback(!err || finalAttempt, {err: err, result: result});
653 }, wrappedResults);
654 };
655 }
656
657 function retryInterval(interval){
658 return function(seriesCallback){
659 setTimeout(function(){
660 seriesCallback(null);
661 }, interval);
662 };
663 }
664
665 while (opts.times) {
666
667 var finalAttempt = !(opts.times-=1);
668 attempts.push(retryAttempt(opts.task, finalAttempt));
669 if(!finalAttempt && opts.interval > 0){
670 attempts.push(retryInterval(opts.interval));
671 }
672 }
673
674 async.series(attempts, function(done, data){
675 data = data[data.length - 1];
676 (wrappedCallback || opts.callback)(data.err, data.result);
677 });
678 }
679
680 // If a callback is passed, run this as a controll flow
681 return opts.callback ? wrappedTask() : wrappedTask;
682 };
683
684 async.waterfall = function (tasks, callback) {
685 callback = _once(callback || noop);
686 if (!_isArray(tasks)) {
687 var err = new Error('First argument to waterfall must be an array of functions');
688 return callback(err);
689 }
690 if (!tasks.length) {
691 return callback();
692 }
693 function wrapIterator(iterator) {
694 return _restParam(function (err, args) {
695 if (err) {
696 callback.apply(null, [err].concat(args));
697 }
698 else {
699 var next = iterator.next();
700 if (next) {
701 args.push(wrapIterator(next));
702 }
703 else {
704 args.push(callback);
705 }
706 ensureAsync(iterator).apply(null, args);
707 }
708 });
709 }
710 wrapIterator(async.iterator(tasks))();
711 };
712
713 function _parallel(eachfn, tasks, callback) {
714 callback = callback || noop;
715 var results = _isArrayLike(tasks) ? [] : {};
716
717 eachfn(tasks, function (task, key, callback) {
718 task(_restParam(function (err, args) {
719 if (args.length <= 1) {
720 args = args[0];
721 }
722 results[key] = args;
723 callback(err);
724 }));
725 }, function (err) {
726 callback(err, results);
727 });
728 }
729
730 async.parallel = function (tasks, callback) {
731 _parallel(async.eachOf, tasks, callback);
732 };
733
734 async.parallelLimit = function(tasks, limit, callback) {
735 _parallel(_eachOfLimit(limit), tasks, callback);
736 };
737
738 async.series = function(tasks, callback) {
739 _parallel(async.eachOfSeries, tasks, callback);
740 };
741
742 async.iterator = function (tasks) {
743 function makeCallback(index) {
744 function fn() {
745 if (tasks.length) {
746 tasks[index].apply(null, arguments);
747 }
748 return fn.next();
749 }
750 fn.next = function () {
751 return (index < tasks.length - 1) ? makeCallback(index + 1): null;
752 };
753 return fn;
754 }
755 return makeCallback(0);
756 };
757
758 async.apply = _restParam(function (fn, args) {
759 return _restParam(function (callArgs) {
760 return fn.apply(
761 null, args.concat(callArgs)
762 );
763 });
764 });
765
766 function _concat(eachfn, arr, fn, callback) {
767 var result = [];
768 eachfn(arr, function (x, index, cb) {
769 fn(x, function (err, y) {
770 result = result.concat(y || []);
771 cb(err);
772 });
773 }, function (err) {
774 callback(err, result);
775 });
776 }
777 async.concat = doParallel(_concat);
778 async.concatSeries = doSeries(_concat);
779
780 async.whilst = function (test, iterator, callback) {
781 callback = callback || noop;
782 if (test()) {
783 var next = _restParam(function(err, args) {
784 if (err) {
785 callback(err);
786 } else if (test.apply(this, args)) {
787 iterator(next);
788 } else {
789 callback.apply(null, [null].concat(args));
790 }
791 });
792 iterator(next);
793 } else {
794 callback(null);
795 }
796 };
797
798 async.doWhilst = function (iterator, test, callback) {
799 var calls = 0;
800 return async.whilst(function() {
801 return ++calls <= 1 || test.apply(this, arguments);
802 }, iterator, callback);
803 };
804
805 async.until = function (test, iterator, callback) {
806 return async.whilst(function() {
807 return !test.apply(this, arguments);
808 }, iterator, callback);
809 };
810
811 async.doUntil = function (iterator, test, callback) {
812 return async.doWhilst(iterator, function() {
813 return !test.apply(this, arguments);
814 }, callback);
815 };
816
817 async.during = function (test, iterator, callback) {
818 callback = callback || noop;
819
820 var next = _restParam(function(err, args) {
821 if (err) {
822 callback(err);
823 } else {
824 args.push(check);
825 test.apply(this, args);
826 }
827 });
828
829 var check = function(err, truth) {
830 if (err) {
831 callback(err);
832 } else if (truth) {
833 iterator(next);
834 } else {
835 callback(null);
836 }
837 };
838
839 test(check);
840 };
841
842 async.doDuring = function (iterator, test, callback) {
843 var calls = 0;
844 async.during(function(next) {
845 if (calls++ < 1) {
846 next(null, true);
847 } else {
848 test.apply(this, arguments);
849 }
850 }, iterator, callback);
851 };
852
853 function _queue(worker, concurrency, payload) {
854 if (concurrency == null) {
855 concurrency = 1;
856 }
857 else if(concurrency === 0) {
858 throw new Error('Concurrency must not be zero');
859 }
860 function _insert(q, data, pos, callback) {
861 if (callback != null && typeof callback !== "function") {
862 throw new Error("task callback must be a function");
863 }
864 q.started = true;
865 if (!_isArray(data)) {
866 data = [data];
867 }
868 if(data.length === 0 && q.idle()) {
869 // call drain immediately if there are no tasks
870 return async.setImmediate(function() {
871 q.drain();
872 });
873 }
874 _arrayEach(data, function(task) {
875 var item = {
876 data: task,
877 callback: callback || noop
878 };
879
880 if (pos) {
881 q.tasks.unshift(item);
882 } else {
883 q.tasks.push(item);
884 }
885
886 if (q.tasks.length === q.concurrency) {
887 q.saturated();
888 }
889 });
890 async.setImmediate(q.process);
891 }
892 function _next(q, tasks) {
893 return function(){
894 workers -= 1;
895
896 var removed = false;
897 var args = arguments;
898 _arrayEach(tasks, function (task) {
899 _arrayEach(workersList, function (worker, index) {
900 if (worker === task && !removed) {
901 workersList.splice(index, 1);
902 removed = true;
903 }
904 });
905
906 task.callback.apply(task, args);
907 });
908 if (q.tasks.length + workers === 0) {
909 q.drain();
910 }
911 q.process();
912 };
913 }
914
915 var workers = 0;
916 var workersList = [];
917 var q = {
918 tasks: [],
919 concurrency: concurrency,
920 payload: payload,
921 saturated: noop,
922 empty: noop,
923 drain: noop,
924 started: false,
925 paused: false,
926 push: function (data, callback) {
927 _insert(q, data, false, callback);
928 },
929 kill: function () {
930 q.drain = noop;
931 q.tasks = [];
932 },
933 unshift: function (data, callback) {
934 _insert(q, data, true, callback);
935 },
936 process: function () {
937 while(!q.paused && workers < q.concurrency && q.tasks.length){
938
939 var tasks = q.payload ?
940 q.tasks.splice(0, q.payload) :
941 q.tasks.splice(0, q.tasks.length);
942
943 var data = _map(tasks, function (task) {
944 return task.data;
945 });
946
947 if (q.tasks.length === 0) {
948 q.empty();
949 }
950 workers += 1;
951 workersList.push(tasks[0]);
952 var cb = only_once(_next(q, tasks));
953 worker(data, cb);
954 }
955 },
956 length: function () {
957 return q.tasks.length;
958 },
959 running: function () {
960 return workers;
961 },
962 workersList: function () {
963 return workersList;
964 },
965 idle: function() {
966 return q.tasks.length + workers === 0;
967 },
968 pause: function () {
969 q.paused = true;
970 },
971 resume: function () {
972 if (q.paused === false) { return; }
973 q.paused = false;
974 var resumeCount = Math.min(q.concurrency, q.tasks.length);
975 // Need to call q.process once per concurrent
976 // worker to preserve full concurrency after pause
977 for (var w = 1; w <= resumeCount; w++) {
978 async.setImmediate(q.process);
979 }
980 }
981 };
982 return q;
983 }
984
985 async.queue = function (worker, concurrency) {
986 var q = _queue(function (items, cb) {
987 worker(items[0], cb);
988 }, concurrency, 1);
989
990 return q;
991 };
992
993 async.priorityQueue = function (worker, concurrency) {
994
995 function _compareTasks(a, b){
996 return a.priority - b.priority;
997 }
998
999 function _binarySearch(sequence, item, compare) {
1000 var beg = -1,
1001 end = sequence.length - 1;
1002 while (beg < end) {
1003 var mid = beg + ((end - beg + 1) >>> 1);
1004 if (compare(item, sequence[mid]) >= 0) {
1005 beg = mid;
1006 } else {
1007 end = mid - 1;
1008 }
1009 }
1010 return beg;
1011 }
1012
1013 function _insert(q, data, priority, callback) {
1014 if (callback != null && typeof callback !== "function") {
1015 throw new Error("task callback must be a function");
1016 }
1017 q.started = true;
1018 if (!_isArray(data)) {
1019 data = [data];
1020 }
1021 if(data.length === 0) {
1022 // call drain immediately if there are no tasks
1023 return async.setImmediate(function() {
1024 q.drain();
1025 });
1026 }
1027 _arrayEach(data, function(task) {
1028 var item = {
1029 data: task,
1030 priority: priority,
1031 callback: typeof callback === 'function' ? callback : noop
1032 };
1033
1034 q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item);
1035
1036 if (q.tasks.length === q.concurrency) {
1037 q.saturated();
1038 }
1039 async.setImmediate(q.process);
1040 });
1041 }
1042
1043 // Start with a normal queue
1044 var q = async.queue(worker, concurrency);
1045
1046 // Override push to accept second parameter representing priority
1047 q.push = function (data, priority, callback) {
1048 _insert(q, data, priority, callback);
1049 };
1050
1051 // Remove unshift function
1052 delete q.unshift;
1053
1054 return q;
1055 };
1056
1057 async.cargo = function (worker, payload) {
1058 return _queue(worker, 1, payload);
1059 };
1060
1061 function _console_fn(name) {
1062 return _restParam(function (fn, args) {
1063 fn.apply(null, args.concat([_restParam(function (err, args) {
1064 if (typeof console === 'object') {
1065 if (err) {
1066 if (console.error) {
1067 console.error(err);
1068 }
1069 }
1070 else if (console[name]) {
1071 _arrayEach(args, function (x) {
1072 console[name](x);
1073 });
1074 }
1075 }
1076 })]));
1077 });
1078 }
1079 async.log = _console_fn('log');
1080 async.dir = _console_fn('dir');
1081 /*async.info = _console_fn('info');
1082 async.warn = _console_fn('warn');
1083 async.error = _console_fn('error');*/
1084
1085 async.memoize = function (fn, hasher) {
1086 var memo = {};
1087 var queues = {};
1088 var has = Object.prototype.hasOwnProperty;
1089 hasher = hasher || identity;
1090 var memoized = _restParam(function memoized(args) {
1091 var callback = args.pop();
1092 var key = hasher.apply(null, args);
1093 if (has.call(memo, key)) {
1094 async.setImmediate(function () {
1095 callback.apply(null, memo[key]);
1096 });
1097 }
1098 else if (has.call(queues, key)) {
1099 queues[key].push(callback);
1100 }
1101 else {
1102 queues[key] = [callback];
1103 fn.apply(null, args.concat([_restParam(function (args) {
1104 memo[key] = args;
1105 var q = queues[key];
1106 delete queues[key];
1107 for (var i = 0, l = q.length; i < l; i++) {
1108 q[i].apply(null, args);
1109 }
1110 })]));
1111 }
1112 });
1113 memoized.memo = memo;
1114 memoized.unmemoized = fn;
1115 return memoized;
1116 };
1117
1118 async.unmemoize = function (fn) {
1119 return function () {
1120 return (fn.unmemoized || fn).apply(null, arguments);
1121 };
1122 };
1123
1124 function _times(mapper) {
1125 return function (count, iterator, callback) {
1126 mapper(_range(count), iterator, callback);
1127 };
1128 }
1129
1130 async.times = _times(async.map);
1131 async.timesSeries = _times(async.mapSeries);
1132 async.timesLimit = function (count, limit, iterator, callback) {
1133 return async.mapLimit(_range(count), limit, iterator, callback);
1134 };
1135
1136 async.seq = function (/* functions... */) {
1137 var fns = arguments;
1138 return _restParam(function (args) {
1139 var that = this;
1140
1141 var callback = args[args.length - 1];
1142 if (typeof callback == 'function') {
1143 args.pop();
1144 } else {
1145 callback = noop;
1146 }
1147
1148 async.reduce(fns, args, function (newargs, fn, cb) {
1149 fn.apply(that, newargs.concat([_restParam(function (err, nextargs) {
1150 cb(err, nextargs);
1151 })]));
1152 },
1153 function (err, results) {
1154 callback.apply(that, [err].concat(results));
1155 });
1156 });
1157 };
1158
1159 async.compose = function (/* functions... */) {
1160 return async.seq.apply(null, Array.prototype.reverse.call(arguments));
1161 };
1162
1163
1164 function _applyEach(eachfn) {
1165 return _restParam(function(fns, args) {
1166 var go = _restParam(function(args) {
1167 var that = this;
1168 var callback = args.pop();
1169 return eachfn(fns, function (fn, _, cb) {
1170 fn.apply(that, args.concat([cb]));
1171 },
1172 callback);
1173 });
1174 if (args.length) {
1175 return go.apply(this, args);
1176 }
1177 else {
1178 return go;
1179 }
1180 });
1181 }
1182
1183 async.applyEach = _applyEach(async.eachOf);
1184 async.applyEachSeries = _applyEach(async.eachOfSeries);
1185
1186
1187 async.forever = function (fn, callback) {
1188 var done = only_once(callback || noop);
1189 var task = ensureAsync(fn);
1190 function next(err) {
1191 if (err) {
1192 return done(err);
1193 }
1194 task(next);
1195 }
1196 next();
1197 };
1198
1199 function ensureAsync(fn) {
1200 return _restParam(function (args) {
1201 var callback = args.pop();
1202 args.push(function () {
1203 var innerArgs = arguments;
1204 if (sync) {
1205 async.setImmediate(function () {
1206 callback.apply(null, innerArgs);
1207 });
1208 } else {
1209 callback.apply(null, innerArgs);
1210 }
1211 });
1212 var sync = true;
1213 fn.apply(this, args);
1214 sync = false;
1215 });
1216 }
1217
1218 async.ensureAsync = ensureAsync;
1219
1220 async.constant = _restParam(function(values) {
1221 var args = [null].concat(values);
1222 return function (callback) {
1223 return callback.apply(this, args);
1224 };
1225 });
1226
1227 async.wrapSync =
1228 async.asyncify = function asyncify(func) {
1229 return _restParam(function (args) {
1230 var callback = args.pop();
1231 var result;
1232 try {
1233 result = func.apply(this, args);
1234 } catch (e) {
1235 return callback(e);
1236 }
1237 // if result is Promise object
1238 if (_isObject(result) && typeof result.then === "function") {
1239 result.then(function(value) {
1240 callback(null, value);
1241 })["catch"](function(err) {
1242 callback(err.message ? err : new Error(err));
1243 });
1244 } else {
1245 callback(null, result);
1246 }
1247 });
1248 };
1249
1250 // Node.js
1251 if (typeof module === 'object' && module.exports) {
1252 module.exports = async;
1253 }
1254 // AMD / RequireJS
1255 else if (typeof define === 'function' && define.amd) {
1256 define([], function () {
1257 return async;
1258 });
1259 }
1260 // included directly via <script> tag
1261 else {
1262 root.async = async;
1263 }
1264
1265}());