UNPKG

21.4 kBJavaScriptView Raw
1/*global setTimeout: false, console: false */
2(function () {
3
4 var async = {};
5
6 // global on the server, window in the browser
7 var root = this,
8 previous_async = root.async;
9
10 async.noConflict = function () {
11 root.async = previous_async;
12 return async;
13 };
14
15 //// cross-browser compatiblity functions ////
16
17 var _forEach = function (arr, iterator) {
18 if (arr.forEach) {
19 return arr.forEach(iterator);
20 }
21 for (var i = 0; i < arr.length; i += 1) {
22 iterator(arr[i], i, arr);
23 }
24 };
25
26 var _map = function (arr, iterator) {
27 if (arr.map) {
28 return arr.map(iterator);
29 }
30 var results = [];
31 _forEach(arr, function (x, i, a) {
32 results.push(iterator(x, i, a));
33 });
34 return results;
35 };
36
37 var _reduce = function (arr, iterator, memo) {
38 if (arr.reduce) {
39 return arr.reduce(iterator, memo);
40 }
41 _forEach(arr, function (x, i, a) {
42 memo = iterator(memo, x, i, a);
43 });
44 return memo;
45 };
46
47 var _keys = function (obj) {
48 if (Object.keys) {
49 return Object.keys(obj);
50 }
51 var keys = [];
52 for (var k in obj) {
53 if (obj.hasOwnProperty(k)) {
54 keys.push(k);
55 }
56 }
57 return keys;
58 };
59
60 //// exported async module functions ////
61
62 //// nextTick implementation with browser-compatible fallback ////
63 if (typeof process === 'undefined' || !(process.nextTick)) {
64 async.nextTick = function (fn) {
65 setTimeout(fn, 0);
66 };
67 }
68 else {
69 async.nextTick = process.nextTick;
70 }
71
72 async.forEach = function (arr, iterator, callback) {
73 callback = callback || function () {};
74 if (!arr.length) {
75 return callback();
76 }
77 var completed = 0;
78 _forEach(arr, function (x) {
79 iterator(x, function (err) {
80 if (err) {
81 callback(err);
82 callback = function () {};
83 }
84 else {
85 completed += 1;
86 if (completed === arr.length) {
87 callback(null);
88 }
89 }
90 });
91 });
92 };
93
94 async.forEachSeries = function (arr, iterator, callback) {
95 callback = callback || function () {};
96 if (!arr.length) {
97 return callback();
98 }
99 var completed = 0;
100 var iterate = function () {
101 iterator(arr[completed], function (err) {
102 if (err) {
103 callback(err);
104 callback = function () {};
105 }
106 else {
107 completed += 1;
108 if (completed === arr.length) {
109 callback(null);
110 }
111 else {
112 iterate();
113 }
114 }
115 });
116 };
117 iterate();
118 };
119
120 async.forEachLimit = function (arr, limit, iterator, callback) {
121 callback = callback || function () {};
122 if (!arr.length || limit <= 0) {
123 return callback();
124 }
125 var completed = 0;
126 var started = 0;
127 var running = 0;
128
129 (function replenish () {
130 if (completed === arr.length) {
131 return callback();
132 }
133
134 while (running < limit && started < arr.length) {
135 started += 1;
136 running += 1;
137 iterator(arr[started - 1], function (err) {
138 if (err) {
139 callback(err);
140 callback = function () {};
141 }
142 else {
143 completed += 1;
144 running -= 1;
145 if (completed === arr.length) {
146 callback();
147 }
148 else {
149 replenish();
150 }
151 }
152 });
153 }
154 })();
155 };
156
157
158 var doParallel = function (fn) {
159 return function () {
160 var args = Array.prototype.slice.call(arguments);
161 return fn.apply(null, [async.forEach].concat(args));
162 };
163 };
164 var doSeries = function (fn) {
165 return function () {
166 var args = Array.prototype.slice.call(arguments);
167 return fn.apply(null, [async.forEachSeries].concat(args));
168 };
169 };
170
171
172 var _asyncMap = function (eachfn, arr, iterator, callback) {
173 var results = [];
174 arr = _map(arr, function (x, i) {
175 return {index: i, value: x};
176 });
177 eachfn(arr, function (x, callback) {
178 iterator(x.value, function (err, v) {
179 results[x.index] = v;
180 callback(err);
181 });
182 }, function (err) {
183 callback(err, results);
184 });
185 };
186 async.map = doParallel(_asyncMap);
187 async.mapSeries = doSeries(_asyncMap);
188
189
190 // reduce only has a series version, as doing reduce in parallel won't
191 // work in many situations.
192 async.reduce = function (arr, memo, iterator, callback) {
193 async.forEachSeries(arr, function (x, callback) {
194 iterator(memo, x, function (err, v) {
195 memo = v;
196 callback(err);
197 });
198 }, function (err) {
199 callback(err, memo);
200 });
201 };
202 // inject alias
203 async.inject = async.reduce;
204 // foldl alias
205 async.foldl = async.reduce;
206
207 async.reduceRight = function (arr, memo, iterator, callback) {
208 var reversed = _map(arr, function (x) {
209 return x;
210 }).reverse();
211 async.reduce(reversed, memo, iterator, callback);
212 };
213 // foldr alias
214 async.foldr = async.reduceRight;
215
216 var _filter = function (eachfn, arr, iterator, callback) {
217 var results = [];
218 arr = _map(arr, function (x, i) {
219 return {index: i, value: x};
220 });
221 eachfn(arr, function (x, callback) {
222 iterator(x.value, function (v) {
223 if (v) {
224 results.push(x);
225 }
226 callback();
227 });
228 }, function (err) {
229 callback(_map(results.sort(function (a, b) {
230 return a.index - b.index;
231 }), function (x) {
232 return x.value;
233 }));
234 });
235 };
236 async.filter = doParallel(_filter);
237 async.filterSeries = doSeries(_filter);
238 // select alias
239 async.select = async.filter;
240 async.selectSeries = async.filterSeries;
241
242 var _reject = function (eachfn, arr, iterator, callback) {
243 var results = [];
244 arr = _map(arr, function (x, i) {
245 return {index: i, value: x};
246 });
247 eachfn(arr, function (x, callback) {
248 iterator(x.value, function (v) {
249 if (!v) {
250 results.push(x);
251 }
252 callback();
253 });
254 }, function (err) {
255 callback(_map(results.sort(function (a, b) {
256 return a.index - b.index;
257 }), function (x) {
258 return x.value;
259 }));
260 });
261 };
262 async.reject = doParallel(_reject);
263 async.rejectSeries = doSeries(_reject);
264
265 var _detect = function (eachfn, arr, iterator, main_callback) {
266 eachfn(arr, function (x, callback) {
267 iterator(x, function (result) {
268 if (result) {
269 main_callback(x);
270 main_callback = function () {};
271 }
272 else {
273 callback();
274 }
275 });
276 }, function (err) {
277 main_callback();
278 });
279 };
280 async.detect = doParallel(_detect);
281 async.detectSeries = doSeries(_detect);
282
283 async.some = function (arr, iterator, main_callback) {
284 async.forEach(arr, function (x, callback) {
285 iterator(x, function (v) {
286 if (v) {
287 main_callback(true);
288 main_callback = function () {};
289 }
290 callback();
291 });
292 }, function (err) {
293 main_callback(false);
294 });
295 };
296 // any alias
297 async.any = async.some;
298
299 async.every = function (arr, iterator, main_callback) {
300 async.forEach(arr, function (x, callback) {
301 iterator(x, function (v) {
302 if (!v) {
303 main_callback(false);
304 main_callback = function () {};
305 }
306 callback();
307 });
308 }, function (err) {
309 main_callback(true);
310 });
311 };
312 // all alias
313 async.all = async.every;
314
315 async.sortBy = function (arr, iterator, callback) {
316 async.map(arr, function (x, callback) {
317 iterator(x, function (err, criteria) {
318 if (err) {
319 callback(err);
320 }
321 else {
322 callback(null, {value: x, criteria: criteria});
323 }
324 });
325 }, function (err, results) {
326 if (err) {
327 return callback(err);
328 }
329 else {
330 var fn = function (left, right) {
331 var a = left.criteria, b = right.criteria;
332 return a < b ? -1 : a > b ? 1 : 0;
333 };
334 callback(null, _map(results.sort(fn), function (x) {
335 return x.value;
336 }));
337 }
338 });
339 };
340
341 async.auto = function (tasks, callback) {
342 callback = callback || function () {};
343 var keys = _keys(tasks);
344 if (!keys.length) {
345 return callback(null);
346 }
347
348 var results = {};
349
350 var listeners = [];
351 var addListener = function (fn) {
352 listeners.unshift(fn);
353 };
354 var removeListener = function (fn) {
355 for (var i = 0; i < listeners.length; i += 1) {
356 if (listeners[i] === fn) {
357 listeners.splice(i, 1);
358 return;
359 }
360 }
361 };
362 var taskComplete = function () {
363 _forEach(listeners.slice(0), function (fn) {
364 fn();
365 });
366 };
367
368 addListener(function () {
369 if (_keys(results).length === keys.length) {
370 callback(null, results);
371 callback = function () {};
372 }
373 });
374
375 _forEach(keys, function (k) {
376 var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k];
377 var taskCallback = function (err) {
378 if (err) {
379 callback(err);
380 // stop subsequent errors hitting callback multiple times
381 callback = function () {};
382 }
383 else {
384 var args = Array.prototype.slice.call(arguments, 1);
385 if (args.length <= 1) {
386 args = args[0];
387 }
388 results[k] = args;
389 taskComplete();
390 }
391 };
392 var requires = task.slice(0, Math.abs(task.length - 1)) || [];
393 var ready = function () {
394 return _reduce(requires, function (a, x) {
395 return (a && results.hasOwnProperty(x));
396 }, true) && !results.hasOwnProperty(k);
397 };
398 if (ready()) {
399 task[task.length - 1](taskCallback, results);
400 }
401 else {
402 var listener = function () {
403 if (ready()) {
404 removeListener(listener);
405 task[task.length - 1](taskCallback, results);
406 }
407 };
408 addListener(listener);
409 }
410 });
411 };
412
413 async.waterfall = function (tasks, callback) {
414 callback = callback || function () {};
415 if (!tasks.length) {
416 return callback();
417 }
418 var wrapIterator = function (iterator) {
419 return function (err) {
420 if (err) {
421 callback(err);
422 callback = function () {};
423 }
424 else {
425 var args = Array.prototype.slice.call(arguments, 1);
426 var next = iterator.next();
427 if (next) {
428 args.push(wrapIterator(next));
429 }
430 else {
431 args.push(callback);
432 }
433 async.nextTick(function () {
434 iterator.apply(null, args);
435 });
436 }
437 };
438 };
439 wrapIterator(async.iterator(tasks))();
440 };
441
442 async.parallel = function (tasks, callback) {
443 callback = callback || function () {};
444 if (tasks.constructor === Array) {
445 async.map(tasks, function (fn, callback) {
446 if (fn) {
447 fn(function (err) {
448 var args = Array.prototype.slice.call(arguments, 1);
449 if (args.length <= 1) {
450 args = args[0];
451 }
452 callback.call(null, err, args);
453 });
454 }
455 }, callback);
456 }
457 else {
458 var results = {};
459 async.forEach(_keys(tasks), function (k, callback) {
460 tasks[k](function (err) {
461 var args = Array.prototype.slice.call(arguments, 1);
462 if (args.length <= 1) {
463 args = args[0];
464 }
465 results[k] = args;
466 callback(err);
467 });
468 }, function (err) {
469 callback(err, results);
470 });
471 }
472 };
473
474 async.series = function (tasks, callback) {
475 callback = callback || function () {};
476 if (tasks.constructor === Array) {
477 async.mapSeries(tasks, function (fn, callback) {
478 if (fn) {
479 fn(function (err) {
480 var args = Array.prototype.slice.call(arguments, 1);
481 if (args.length <= 1) {
482 args = args[0];
483 }
484 callback.call(null, err, args);
485 });
486 }
487 }, callback);
488 }
489 else {
490 var results = {};
491 async.forEachSeries(_keys(tasks), function (k, callback) {
492 tasks[k](function (err) {
493 var args = Array.prototype.slice.call(arguments, 1);
494 if (args.length <= 1) {
495 args = args[0];
496 }
497 results[k] = args;
498 callback(err);
499 });
500 }, function (err) {
501 callback(err, results);
502 });
503 }
504 };
505
506 async.iterator = function (tasks) {
507 var makeCallback = function (index) {
508 var fn = function () {
509 if (tasks.length) {
510 tasks[index].apply(null, arguments);
511 }
512 return fn.next();
513 };
514 fn.next = function () {
515 return (index < tasks.length - 1) ? makeCallback(index + 1): null;
516 };
517 return fn;
518 };
519 return makeCallback(0);
520 };
521
522 async.apply = function (fn) {
523 var args = Array.prototype.slice.call(arguments, 1);
524 return function () {
525 return fn.apply(
526 null, args.concat(Array.prototype.slice.call(arguments))
527 );
528 };
529 };
530
531 var _concat = function (eachfn, arr, fn, callback) {
532 var r = [];
533 eachfn(arr, function (x, cb) {
534 fn(x, function (err, y) {
535 r = r.concat(y || []);
536 cb(err);
537 });
538 }, function (err) {
539 callback(err, r);
540 });
541 };
542 async.concat = doParallel(_concat);
543 async.concatSeries = doSeries(_concat);
544
545 async.whilst = function (test, iterator, callback) {
546 if (test()) {
547 iterator(function (err) {
548 if (err) {
549 return callback(err);
550 }
551 async.whilst(test, iterator, callback);
552 });
553 }
554 else {
555 callback();
556 }
557 };
558
559 async.until = function (test, iterator, callback) {
560 if (!test()) {
561 iterator(function (err) {
562 if (err) {
563 return callback(err);
564 }
565 async.until(test, iterator, callback);
566 });
567 }
568 else {
569 callback();
570 }
571 };
572
573 async.queue = function (worker, concurrency) {
574 var workers = 0;
575 var q = {
576 tasks: [],
577 concurrency: concurrency,
578 saturated: null,
579 empty: null,
580 drain: null,
581 push: function (data, callback) {
582 if(data.constructor !== Array) {
583 data = [data];
584 }
585 _forEach(data, function(task) {
586 q.tasks.push({
587 data: task,
588 callback: typeof callback === 'function' ? callback : null
589 });
590 if (q.saturated && q.tasks.length == concurrency) {
591 q.saturated();
592 }
593 async.nextTick(q.process);
594 });
595 },
596 process: function () {
597 if (workers < q.concurrency && q.tasks.length) {
598 var task = q.tasks.shift();
599 if(q.empty && q.tasks.length == 0) q.empty();
600 workers += 1;
601 worker(task.data, function () {
602 workers -= 1;
603 if (task.callback) {
604 task.callback.apply(task, arguments);
605 }
606 if(q.drain && q.tasks.length + workers == 0) q.drain();
607 q.process();
608 });
609 }
610 },
611 length: function () {
612 return q.tasks.length;
613 },
614 running: function () {
615 return workers;
616 }
617 };
618 return q;
619 };
620
621 var _console_fn = function (name) {
622 return function (fn) {
623 var args = Array.prototype.slice.call(arguments, 1);
624 fn.apply(null, args.concat([function (err) {
625 var args = Array.prototype.slice.call(arguments, 1);
626 if (typeof console !== 'undefined') {
627 if (err) {
628 if (console.error) {
629 console.error(err);
630 }
631 }
632 else if (console[name]) {
633 _forEach(args, function (x) {
634 console[name](x);
635 });
636 }
637 }
638 }]));
639 };
640 };
641 async.log = _console_fn('log');
642 async.dir = _console_fn('dir');
643 /*async.info = _console_fn('info');
644 async.warn = _console_fn('warn');
645 async.error = _console_fn('error');*/
646
647 async.memoize = function (fn, hasher) {
648 var memo = {};
649 var queues = {};
650 hasher = hasher || function (x) {
651 return x;
652 };
653 var memoized = function () {
654 var args = Array.prototype.slice.call(arguments);
655 var callback = args.pop();
656 var key = hasher.apply(null, args);
657 if (key in memo) {
658 callback.apply(null, memo[key]);
659 }
660 else if (key in queues) {
661 queues[key].push(callback);
662 }
663 else {
664 queues[key] = [callback];
665 fn.apply(null, args.concat([function () {
666 memo[key] = arguments;
667 var q = queues[key];
668 delete queues[key];
669 for (var i = 0, l = q.length; i < l; i++) {
670 q[i].apply(null, arguments);
671 }
672 }]));
673 }
674 };
675 memoized.unmemoized = fn;
676 return memoized;
677 };
678
679 async.unmemoize = function (fn) {
680 return function () {
681 return (fn.unmemoized || fn).apply(null, arguments);
682 };
683 };
684
685 // AMD / RequireJS
686 if (typeof define !== 'undefined' && define.amd) {
687 define('async', [], function () {
688 return async;
689 });
690 }
691 // Node.js
692 else if (typeof module !== 'undefined' && module.exports) {
693 module.exports = async;
694 }
695 // included directly via <script> tag
696 else {
697 root.async = async;
698 }
699
700}());
\No newline at end of file