You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1123 lines
34 KiB

7 years ago
  1. /*!
  2. * async
  3. * https://github.com/caolan/async
  4. *
  5. * Copyright 2010-2014 Caolan McMahon
  6. * Released under the MIT license
  7. */
  8. /*jshint onevar: false, indent:4 */
  9. /*global setImmediate: false, setTimeout: false, console: false */
  10. (function () {
  11. var async = {};
  12. // global on the server, window in the browser
  13. var root, previous_async;
  14. root = this;
  15. if (root != null) {
  16. previous_async = root.async;
  17. }
  18. async.noConflict = function () {
  19. root.async = previous_async;
  20. return async;
  21. };
  22. function only_once(fn) {
  23. var called = false;
  24. return function() {
  25. if (called) throw new Error("Callback was already called.");
  26. called = true;
  27. fn.apply(root, arguments);
  28. }
  29. }
  30. //// cross-browser compatiblity functions ////
  31. var _toString = Object.prototype.toString;
  32. var _isArray = Array.isArray || function (obj) {
  33. return _toString.call(obj) === '[object Array]';
  34. };
  35. var _each = function (arr, iterator) {
  36. if (arr.forEach) {
  37. return arr.forEach(iterator);
  38. }
  39. for (var i = 0; i < arr.length; i += 1) {
  40. iterator(arr[i], i, arr);
  41. }
  42. };
  43. var _map = function (arr, iterator) {
  44. if (arr.map) {
  45. return arr.map(iterator);
  46. }
  47. var results = [];
  48. _each(arr, function (x, i, a) {
  49. results.push(iterator(x, i, a));
  50. });
  51. return results;
  52. };
  53. var _reduce = function (arr, iterator, memo) {
  54. if (arr.reduce) {
  55. return arr.reduce(iterator, memo);
  56. }
  57. _each(arr, function (x, i, a) {
  58. memo = iterator(memo, x, i, a);
  59. });
  60. return memo;
  61. };
  62. var _keys = function (obj) {
  63. if (Object.keys) {
  64. return Object.keys(obj);
  65. }
  66. var keys = [];
  67. for (var k in obj) {
  68. if (obj.hasOwnProperty(k)) {
  69. keys.push(k);
  70. }
  71. }
  72. return keys;
  73. };
  74. //// exported async module functions ////
  75. //// nextTick implementation with browser-compatible fallback ////
  76. if (typeof process === 'undefined' || !(process.nextTick)) {
  77. if (typeof setImmediate === 'function') {
  78. async.nextTick = function (fn) {
  79. // not a direct alias for IE10 compatibility
  80. setImmediate(fn);
  81. };
  82. async.setImmediate = async.nextTick;
  83. }
  84. else {
  85. async.nextTick = function (fn) {
  86. setTimeout(fn, 0);
  87. };
  88. async.setImmediate = async.nextTick;
  89. }
  90. }
  91. else {
  92. async.nextTick = process.nextTick;
  93. if (typeof setImmediate !== 'undefined') {
  94. async.setImmediate = function (fn) {
  95. // not a direct alias for IE10 compatibility
  96. setImmediate(fn);
  97. };
  98. }
  99. else {
  100. async.setImmediate = async.nextTick;
  101. }
  102. }
  103. async.each = function (arr, iterator, callback) {
  104. callback = callback || function () {};
  105. if (!arr.length) {
  106. return callback();
  107. }
  108. var completed = 0;
  109. _each(arr, function (x) {
  110. iterator(x, only_once(done) );
  111. });
  112. function done(err) {
  113. if (err) {
  114. callback(err);
  115. callback = function () {};
  116. }
  117. else {
  118. completed += 1;
  119. if (completed >= arr.length) {
  120. callback();
  121. }
  122. }
  123. }
  124. };
  125. async.forEach = async.each;
  126. async.eachSeries = function (arr, iterator, callback) {
  127. callback = callback || function () {};
  128. if (!arr.length) {
  129. return callback();
  130. }
  131. var completed = 0;
  132. var iterate = function () {
  133. iterator(arr[completed], function (err) {
  134. if (err) {
  135. callback(err);
  136. callback = function () {};
  137. }
  138. else {
  139. completed += 1;
  140. if (completed >= arr.length) {
  141. callback();
  142. }
  143. else {
  144. iterate();
  145. }
  146. }
  147. });
  148. };
  149. iterate();
  150. };
  151. async.forEachSeries = async.eachSeries;
  152. async.eachLimit = function (arr, limit, iterator, callback) {
  153. var fn = _eachLimit(limit);
  154. fn.apply(null, [arr, iterator, callback]);
  155. };
  156. async.forEachLimit = async.eachLimit;
  157. var _eachLimit = function (limit) {
  158. return function (arr, iterator, callback) {
  159. callback = callback || function () {};
  160. if (!arr.length || limit <= 0) {
  161. return callback();
  162. }
  163. var completed = 0;
  164. var started = 0;
  165. var running = 0;
  166. (function replenish () {
  167. if (completed >= arr.length) {
  168. return callback();
  169. }
  170. while (running < limit && started < arr.length) {
  171. started += 1;
  172. running += 1;
  173. iterator(arr[started - 1], function (err) {
  174. if (err) {
  175. callback(err);
  176. callback = function () {};
  177. }
  178. else {
  179. completed += 1;
  180. running -= 1;
  181. if (completed >= arr.length) {
  182. callback();
  183. }
  184. else {
  185. replenish();
  186. }
  187. }
  188. });
  189. }
  190. })();
  191. };
  192. };
  193. var doParallel = function (fn) {
  194. return function () {
  195. var args = Array.prototype.slice.call(arguments);
  196. return fn.apply(null, [async.each].concat(args));
  197. };
  198. };
  199. var doParallelLimit = function(limit, fn) {
  200. return function () {
  201. var args = Array.prototype.slice.call(arguments);
  202. return fn.apply(null, [_eachLimit(limit)].concat(args));
  203. };
  204. };
  205. var doSeries = function (fn) {
  206. return function () {
  207. var args = Array.prototype.slice.call(arguments);
  208. return fn.apply(null, [async.eachSeries].concat(args));
  209. };
  210. };
  211. var _asyncMap = function (eachfn, arr, iterator, callback) {
  212. arr = _map(arr, function (x, i) {
  213. return {index: i, value: x};
  214. });
  215. if (!callback) {
  216. eachfn(arr, function (x, callback) {
  217. iterator(x.value, function (err) {
  218. callback(err);
  219. });
  220. });
  221. } else {
  222. var results = [];
  223. eachfn(arr, function (x, callback) {
  224. iterator(x.value, function (err, v) {
  225. results[x.index] = v;
  226. callback(err);
  227. });
  228. }, function (err) {
  229. callback(err, results);
  230. });
  231. }
  232. };
  233. async.map = doParallel(_asyncMap);
  234. async.mapSeries = doSeries(_asyncMap);
  235. async.mapLimit = function (arr, limit, iterator, callback) {
  236. return _mapLimit(limit)(arr, iterator, callback);
  237. };
  238. var _mapLimit = function(limit) {
  239. return doParallelLimit(limit, _asyncMap);
  240. };
  241. // reduce only has a series version, as doing reduce in parallel won't
  242. // work in many situations.
  243. async.reduce = function (arr, memo, iterator, callback) {
  244. async.eachSeries(arr, function (x, callback) {
  245. iterator(memo, x, function (err, v) {
  246. memo = v;
  247. callback(err);
  248. });
  249. }, function (err) {
  250. callback(err, memo);
  251. });
  252. };
  253. // inject alias
  254. async.inject = async.reduce;
  255. // foldl alias
  256. async.foldl = async.reduce;
  257. async.reduceRight = function (arr, memo, iterator, callback) {
  258. var reversed = _map(arr, function (x) {
  259. return x;
  260. }).reverse();
  261. async.reduce(reversed, memo, iterator, callback);
  262. };
  263. // foldr alias
  264. async.foldr = async.reduceRight;
  265. var _filter = function (eachfn, arr, iterator, callback) {
  266. var results = [];
  267. arr = _map(arr, function (x, i) {
  268. return {index: i, value: x};
  269. });
  270. eachfn(arr, function (x, callback) {
  271. iterator(x.value, function (v) {
  272. if (v) {
  273. results.push(x);
  274. }
  275. callback();
  276. });
  277. }, function (err) {
  278. callback(_map(results.sort(function (a, b) {
  279. return a.index - b.index;
  280. }), function (x) {
  281. return x.value;
  282. }));
  283. });
  284. };
  285. async.filter = doParallel(_filter);
  286. async.filterSeries = doSeries(_filter);
  287. // select alias
  288. async.select = async.filter;
  289. async.selectSeries = async.filterSeries;
  290. var _reject = function (eachfn, arr, iterator, callback) {
  291. var results = [];
  292. arr = _map(arr, function (x, i) {
  293. return {index: i, value: x};
  294. });
  295. eachfn(arr, function (x, callback) {
  296. iterator(x.value, function (v) {
  297. if (!v) {
  298. results.push(x);
  299. }
  300. callback();
  301. });
  302. }, function (err) {
  303. callback(_map(results.sort(function (a, b) {
  304. return a.index - b.index;
  305. }), function (x) {
  306. return x.value;
  307. }));
  308. });
  309. };
  310. async.reject = doParallel(_reject);
  311. async.rejectSeries = doSeries(_reject);
  312. var _detect = function (eachfn, arr, iterator, main_callback) {
  313. eachfn(arr, function (x, callback) {
  314. iterator(x, function (result) {
  315. if (result) {
  316. main_callback(x);
  317. main_callback = function () {};
  318. }
  319. else {
  320. callback();
  321. }
  322. });
  323. }, function (err) {
  324. main_callback();
  325. });
  326. };
  327. async.detect = doParallel(_detect);
  328. async.detectSeries = doSeries(_detect);
  329. async.some = function (arr, iterator, main_callback) {
  330. async.each(arr, function (x, callback) {
  331. iterator(x, function (v) {
  332. if (v) {
  333. main_callback(true);
  334. main_callback = function () {};
  335. }
  336. callback();
  337. });
  338. }, function (err) {
  339. main_callback(false);
  340. });
  341. };
  342. // any alias
  343. async.any = async.some;
  344. async.every = function (arr, iterator, main_callback) {
  345. async.each(arr, function (x, callback) {
  346. iterator(x, function (v) {
  347. if (!v) {
  348. main_callback(false);
  349. main_callback = function () {};
  350. }
  351. callback();
  352. });
  353. }, function (err) {
  354. main_callback(true);
  355. });
  356. };
  357. // all alias
  358. async.all = async.every;
  359. async.sortBy = function (arr, iterator, callback) {
  360. async.map(arr, function (x, callback) {
  361. iterator(x, function (err, criteria) {
  362. if (err) {
  363. callback(err);
  364. }
  365. else {
  366. callback(null, {value: x, criteria: criteria});
  367. }
  368. });
  369. }, function (err, results) {
  370. if (err) {
  371. return callback(err);
  372. }
  373. else {
  374. var fn = function (left, right) {
  375. var a = left.criteria, b = right.criteria;
  376. return a < b ? -1 : a > b ? 1 : 0;
  377. };
  378. callback(null, _map(results.sort(fn), function (x) {
  379. return x.value;
  380. }));
  381. }
  382. });
  383. };
  384. async.auto = function (tasks, callback) {
  385. callback = callback || function () {};
  386. var keys = _keys(tasks);
  387. var remainingTasks = keys.length
  388. if (!remainingTasks) {
  389. return callback();
  390. }
  391. var results = {};
  392. var listeners = [];
  393. var addListener = function (fn) {
  394. listeners.unshift(fn);
  395. };
  396. var removeListener = function (fn) {
  397. for (var i = 0; i < listeners.length; i += 1) {
  398. if (listeners[i] === fn) {
  399. listeners.splice(i, 1);
  400. return;
  401. }
  402. }
  403. };
  404. var taskComplete = function () {
  405. remainingTasks--
  406. _each(listeners.slice(0), function (fn) {
  407. fn();
  408. });
  409. };
  410. addListener(function () {
  411. if (!remainingTasks) {
  412. var theCallback = callback;
  413. // prevent final callback from calling itself if it errors
  414. callback = function () {};
  415. theCallback(null, results);
  416. }
  417. });
  418. _each(keys, function (k) {
  419. var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
  420. var taskCallback = function (err) {
  421. var args = Array.prototype.slice.call(arguments, 1);
  422. if (args.length <= 1) {
  423. args = args[0];
  424. }
  425. if (err) {
  426. var safeResults = {};
  427. _each(_keys(results), function(rkey) {
  428. safeResults[rkey] = results[rkey];
  429. });
  430. safeResults[k] = args;
  431. callback(err, safeResults);
  432. // stop subsequent errors hitting callback multiple times
  433. callback = function () {};
  434. }
  435. else {
  436. results[k] = args;
  437. async.setImmediate(taskComplete);
  438. }
  439. };
  440. var requires = task.slice(0, Math.abs(task.length - 1)) || [];
  441. var ready = function () {
  442. return _reduce(requires, function (a, x) {
  443. return (a && results.hasOwnProperty(x));
  444. }, true) && !results.hasOwnProperty(k);
  445. };
  446. if (ready()) {
  447. task[task.length - 1](taskCallback, results);
  448. }
  449. else {
  450. var listener = function () {
  451. if (ready()) {
  452. removeListener(listener);
  453. task[task.length - 1](taskCallback, results);
  454. }
  455. };
  456. addListener(listener);
  457. }
  458. });
  459. };
  460. async.retry = function(times, task, callback) {
  461. var DEFAULT_TIMES = 5;
  462. var attempts = [];
  463. // Use defaults if times not passed
  464. if (typeof times === 'function') {
  465. callback = task;
  466. task = times;
  467. times = DEFAULT_TIMES;
  468. }
  469. // Make sure times is a number
  470. times = parseInt(times, 10) || DEFAULT_TIMES;
  471. var wrappedTask = function(wrappedCallback, wrappedResults) {
  472. var retryAttempt = function(task, finalAttempt) {
  473. return function(seriesCallback) {
  474. task(function(err, result){
  475. seriesCallback(!err || finalAttempt, {err: err, result: result});
  476. }, wrappedResults);
  477. };
  478. };
  479. while (times) {
  480. attempts.push(retryAttempt(task, !(times-=1)));
  481. }
  482. async.series(attempts, function(done, data){
  483. data = data[data.length - 1];
  484. (wrappedCallback || callback)(data.err, data.result);
  485. });
  486. }
  487. // If a callback is passed, run this as a controll flow
  488. return callback ? wrappedTask() : wrappedTask
  489. };
  490. async.waterfall = function (tasks, callback) {
  491. callback = callback || function () {};
  492. if (!_isArray(tasks)) {
  493. var err = new Error('First argument to waterfall must be an array of functions');
  494. return callback(err);
  495. }
  496. if (!tasks.length) {
  497. return callback();
  498. }
  499. var wrapIterator = function (iterator) {
  500. return function (err) {
  501. if (err) {
  502. callback.apply(null, arguments);
  503. callback = function () {};
  504. }
  505. else {
  506. var args = Array.prototype.slice.call(arguments, 1);
  507. var next = iterator.next();
  508. if (next) {
  509. args.push(wrapIterator(next));
  510. }
  511. else {
  512. args.push(callback);
  513. }
  514. async.setImmediate(function () {
  515. iterator.apply(null, args);
  516. });
  517. }
  518. };
  519. };
  520. wrapIterator(async.iterator(tasks))();
  521. };
  522. var _parallel = function(eachfn, tasks, callback) {
  523. callback = callback || function () {};
  524. if (_isArray(tasks)) {
  525. eachfn.map(tasks, function (fn, callback) {
  526. if (fn) {
  527. fn(function (err) {
  528. var args = Array.prototype.slice.call(arguments, 1);
  529. if (args.length <= 1) {
  530. args = args[0];
  531. }
  532. callback.call(null, err, args);
  533. });
  534. }
  535. }, callback);
  536. }
  537. else {
  538. var results = {};
  539. eachfn.each(_keys(tasks), function (k, callback) {
  540. tasks[k](function (err) {
  541. var args = Array.prototype.slice.call(arguments, 1);
  542. if (args.length <= 1) {
  543. args = args[0];
  544. }
  545. results[k] = args;
  546. callback(err);
  547. });
  548. }, function (err) {
  549. callback(err, results);
  550. });
  551. }
  552. };
  553. async.parallel = function (tasks, callback) {
  554. _parallel({ map: async.map, each: async.each }, tasks, callback);
  555. };
  556. async.parallelLimit = function(tasks, limit, callback) {
  557. _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);
  558. };
  559. async.series = function (tasks, callback) {
  560. callback = callback || function () {};
  561. if (_isArray(tasks)) {
  562. async.mapSeries(tasks, function (fn, callback) {
  563. if (fn) {
  564. fn(function (err) {
  565. var args = Array.prototype.slice.call(arguments, 1);
  566. if (args.length <= 1) {
  567. args = args[0];
  568. }
  569. callback.call(null, err, args);
  570. });
  571. }
  572. }, callback);
  573. }
  574. else {
  575. var results = {};
  576. async.eachSeries(_keys(tasks), function (k, callback) {
  577. tasks[k](function (err) {
  578. var args = Array.prototype.slice.call(arguments, 1);
  579. if (args.length <= 1) {
  580. args = args[0];
  581. }
  582. results[k] = args;
  583. callback(err);
  584. });
  585. }, function (err) {
  586. callback(err, results);
  587. });
  588. }
  589. };
  590. async.iterator = function (tasks) {
  591. var makeCallback = function (index) {
  592. var fn = function () {
  593. if (tasks.length) {
  594. tasks[index].apply(null, arguments);
  595. }
  596. return fn.next();
  597. };
  598. fn.next = function () {
  599. return (index < tasks.length - 1) ? makeCallback(index + 1): null;
  600. };
  601. return fn;
  602. };
  603. return makeCallback(0);
  604. };
  605. async.apply = function (fn) {
  606. var args = Array.prototype.slice.call(arguments, 1);
  607. return function () {
  608. return fn.apply(
  609. null, args.concat(Array.prototype.slice.call(arguments))
  610. );
  611. };
  612. };
  613. var _concat = function (eachfn, arr, fn, callback) {
  614. var r = [];
  615. eachfn(arr, function (x, cb) {
  616. fn(x, function (err, y) {
  617. r = r.concat(y || []);
  618. cb(err);
  619. });
  620. }, function (err) {
  621. callback(err, r);
  622. });
  623. };
  624. async.concat = doParallel(_concat);
  625. async.concatSeries = doSeries(_concat);
  626. async.whilst = function (test, iterator, callback) {
  627. if (test()) {
  628. iterator(function (err) {
  629. if (err) {
  630. return callback(err);
  631. }
  632. async.whilst(test, iterator, callback);
  633. });
  634. }
  635. else {
  636. callback();
  637. }
  638. };
  639. async.doWhilst = function (iterator, test, callback) {
  640. iterator(function (err) {
  641. if (err) {
  642. return callback(err);
  643. }
  644. var args = Array.prototype.slice.call(arguments, 1);
  645. if (test.apply(null, args)) {
  646. async.doWhilst(iterator, test, callback);
  647. }
  648. else {
  649. callback();
  650. }
  651. });
  652. };
  653. async.until = function (test, iterator, callback) {
  654. if (!test()) {
  655. iterator(function (err) {
  656. if (err) {
  657. return callback(err);
  658. }
  659. async.until(test, iterator, callback);
  660. });
  661. }
  662. else {
  663. callback();
  664. }
  665. };
  666. async.doUntil = function (iterator, test, callback) {
  667. iterator(function (err) {
  668. if (err) {
  669. return callback(err);
  670. }
  671. var args = Array.prototype.slice.call(arguments, 1);
  672. if (!test.apply(null, args)) {
  673. async.doUntil(iterator, test, callback);
  674. }
  675. else {
  676. callback();
  677. }
  678. });
  679. };
  680. async.queue = function (worker, concurrency) {
  681. if (concurrency === undefined) {
  682. concurrency = 1;
  683. }
  684. function _insert(q, data, pos, callback) {
  685. if (!q.started){
  686. q.started = true;
  687. }
  688. if (!_isArray(data)) {
  689. data = [data];
  690. }
  691. if(data.length == 0) {
  692. // call drain immediately if there are no tasks
  693. return async.setImmediate(function() {
  694. if (q.drain) {
  695. q.drain();
  696. }
  697. });
  698. }
  699. _each(data, function(task) {
  700. var item = {
  701. data: task,
  702. callback: typeof callback === 'function' ? callback : null
  703. };
  704. if (pos) {
  705. q.tasks.unshift(item);
  706. } else {
  707. q.tasks.push(item);
  708. }
  709. if (q.saturated && q.tasks.length === q.concurrency) {
  710. q.saturated();
  711. }
  712. async.setImmediate(q.process);
  713. });
  714. }
  715. var workers = 0;
  716. var q = {
  717. tasks: [],
  718. concurrency: concurrency,
  719. saturated: null,
  720. empty: null,
  721. drain: null,
  722. started: false,
  723. paused: false,
  724. push: function (data, callback) {
  725. _insert(q, data, false, callback);
  726. },
  727. kill: function () {
  728. q.drain = null;
  729. q.tasks = [];
  730. },
  731. unshift: function (data, callback) {
  732. _insert(q, data, true, callback);
  733. },
  734. process: function () {
  735. if (!q.paused && workers < q.concurrency && q.tasks.length) {
  736. var task = q.tasks.shift();
  737. if (q.empty && q.tasks.length === 0) {
  738. q.empty();
  739. }
  740. workers += 1;
  741. var next = function () {
  742. workers -= 1;
  743. if (task.callback) {
  744. task.callback.apply(task, arguments);
  745. }
  746. if (q.drain && q.tasks.length + workers === 0) {
  747. q.drain();
  748. }
  749. q.process();
  750. };
  751. var cb = only_once(next);
  752. worker(task.data, cb);
  753. }
  754. },
  755. length: function () {
  756. return q.tasks.length;
  757. },
  758. running: function () {
  759. return workers;
  760. },
  761. idle: function() {
  762. return q.tasks.length + workers === 0;
  763. },
  764. pause: function () {
  765. if (q.paused === true) { return; }
  766. q.paused = true;
  767. q.process();
  768. },
  769. resume: function () {
  770. if (q.paused === false) { return; }
  771. q.paused = false;
  772. q.process();
  773. }
  774. };
  775. return q;
  776. };
  777. async.priorityQueue = function (worker, concurrency) {
  778. function _compareTasks(a, b){
  779. return a.priority - b.priority;
  780. };
  781. function _binarySearch(sequence, item, compare) {
  782. var beg = -1,
  783. end = sequence.length - 1;
  784. while (beg < end) {
  785. var mid = beg + ((end - beg + 1) >>> 1);
  786. if (compare(item, sequence[mid]) >= 0) {
  787. beg = mid;
  788. } else {
  789. end = mid - 1;
  790. }
  791. }
  792. return beg;
  793. }
  794. function _insert(q, data, priority, callback) {
  795. if (!q.started){
  796. q.started = true;
  797. }
  798. if (!_isArray(data)) {
  799. data = [data];
  800. }
  801. if(data.length == 0) {
  802. // call drain immediately if there are no tasks
  803. return async.setImmediate(function() {
  804. if (q.drain) {
  805. q.drain();
  806. }
  807. });
  808. }
  809. _each(data, function(task) {
  810. var item = {
  811. data: task,
  812. priority: priority,
  813. callback: typeof callback === 'function' ? callback : null
  814. };
  815. q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item);
  816. if (q.saturated && q.tasks.length === q.concurrency) {
  817. q.saturated();
  818. }
  819. async.setImmediate(q.process);
  820. });
  821. }
  822. // Start with a normal queue
  823. var q = async.queue(worker, concurrency);
  824. // Override push to accept second parameter representing priority
  825. q.push = function (data, priority, callback) {
  826. _insert(q, data, priority, callback);
  827. };
  828. // Remove unshift function
  829. delete q.unshift;
  830. return q;
  831. };
  832. async.cargo = function (worker, payload) {
  833. var working = false,
  834. tasks = [];
  835. var cargo = {
  836. tasks: tasks,
  837. payload: payload,
  838. saturated: null,
  839. empty: null,
  840. drain: null,
  841. drained: true,
  842. push: function (data, callback) {
  843. if (!_isArray(data)) {
  844. data = [data];
  845. }
  846. _each(data, function(task) {
  847. tasks.push({
  848. data: task,
  849. callback: typeof callback === 'function' ? callback : null
  850. });
  851. cargo.drained = false;
  852. if (cargo.saturated && tasks.length === payload) {
  853. cargo.saturated();
  854. }
  855. });
  856. async.setImmediate(cargo.process);
  857. },
  858. process: function process() {
  859. if (working) return;
  860. if (tasks.length === 0) {
  861. if(cargo.drain && !cargo.drained) cargo.drain();
  862. cargo.drained = true;
  863. return;
  864. }
  865. var ts = typeof payload === 'number'
  866. ? tasks.splice(0, payload)
  867. : tasks.splice(0, tasks.length);
  868. var ds = _map(ts, function (task) {
  869. return task.data;
  870. });
  871. if(cargo.empty) cargo.empty();
  872. working = true;
  873. worker(ds, function () {
  874. working = false;
  875. var args = arguments;
  876. _each(ts, function (data) {
  877. if (data.callback) {
  878. data.callback.apply(null, args);
  879. }
  880. });
  881. process();
  882. });
  883. },
  884. length: function () {
  885. return tasks.length;
  886. },
  887. running: function () {
  888. return working;
  889. }
  890. };
  891. return cargo;
  892. };
  893. var _console_fn = function (name) {
  894. return function (fn) {
  895. var args = Array.prototype.slice.call(arguments, 1);
  896. fn.apply(null, args.concat([function (err) {
  897. var args = Array.prototype.slice.call(arguments, 1);
  898. if (typeof console !== 'undefined') {
  899. if (err) {
  900. if (console.error) {
  901. console.error(err);
  902. }
  903. }
  904. else if (console[name]) {
  905. _each(args, function (x) {
  906. console[name](x);
  907. });
  908. }
  909. }
  910. }]));
  911. };
  912. };
  913. async.log = _console_fn('log');
  914. async.dir = _console_fn('dir');
  915. /*async.info = _console_fn('info');
  916. async.warn = _console_fn('warn');
  917. async.error = _console_fn('error');*/
  918. async.memoize = function (fn, hasher) {
  919. var memo = {};
  920. var queues = {};
  921. hasher = hasher || function (x) {
  922. return x;
  923. };
  924. var memoized = function () {
  925. var args = Array.prototype.slice.call(arguments);
  926. var callback = args.pop();
  927. var key = hasher.apply(null, args);
  928. if (key in memo) {
  929. async.nextTick(function () {
  930. callback.apply(null, memo[key]);
  931. });
  932. }
  933. else if (key in queues) {
  934. queues[key].push(callback);
  935. }
  936. else {
  937. queues[key] = [callback];
  938. fn.apply(null, args.concat([function () {
  939. memo[key] = arguments;
  940. var q = queues[key];
  941. delete queues[key];
  942. for (var i = 0, l = q.length; i < l; i++) {
  943. q[i].apply(null, arguments);
  944. }
  945. }]));
  946. }
  947. };
  948. memoized.memo = memo;
  949. memoized.unmemoized = fn;
  950. return memoized;
  951. };
  952. async.unmemoize = function (fn) {
  953. return function () {
  954. return (fn.unmemoized || fn).apply(null, arguments);
  955. };
  956. };
  957. async.times = function (count, iterator, callback) {
  958. var counter = [];
  959. for (var i = 0; i < count; i++) {
  960. counter.push(i);
  961. }
  962. return async.map(counter, iterator, callback);
  963. };
  964. async.timesSeries = function (count, iterator, callback) {
  965. var counter = [];
  966. for (var i = 0; i < count; i++) {
  967. counter.push(i);
  968. }
  969. return async.mapSeries(counter, iterator, callback);
  970. };
  971. async.seq = function (/* functions... */) {
  972. var fns = arguments;
  973. return function () {
  974. var that = this;
  975. var args = Array.prototype.slice.call(arguments);
  976. var callback = args.pop();
  977. async.reduce(fns, args, function (newargs, fn, cb) {
  978. fn.apply(that, newargs.concat([function () {
  979. var err = arguments[0];
  980. var nextargs = Array.prototype.slice.call(arguments, 1);
  981. cb(err, nextargs);
  982. }]))
  983. },
  984. function (err, results) {
  985. callback.apply(that, [err].concat(results));
  986. });
  987. };
  988. };
  989. async.compose = function (/* functions... */) {
  990. return async.seq.apply(null, Array.prototype.reverse.call(arguments));
  991. };
  992. var _applyEach = function (eachfn, fns /*args...*/) {
  993. var go = function () {
  994. var that = this;
  995. var args = Array.prototype.slice.call(arguments);
  996. var callback = args.pop();
  997. return eachfn(fns, function (fn, cb) {
  998. fn.apply(that, args.concat([cb]));
  999. },
  1000. callback);
  1001. };
  1002. if (arguments.length > 2) {
  1003. var args = Array.prototype.slice.call(arguments, 2);
  1004. return go.apply(this, args);
  1005. }
  1006. else {
  1007. return go;
  1008. }
  1009. };
  1010. async.applyEach = doParallel(_applyEach);
  1011. async.applyEachSeries = doSeries(_applyEach);
  1012. async.forever = function (fn, callback) {
  1013. function next(err) {
  1014. if (err) {
  1015. if (callback) {
  1016. return callback(err);
  1017. }
  1018. throw err;
  1019. }
  1020. fn(next);
  1021. }
  1022. next();
  1023. };
  1024. // Node.js
  1025. if (typeof module !== 'undefined' && module.exports) {
  1026. module.exports = async;
  1027. }
  1028. // AMD / RequireJS
  1029. else if (typeof define !== 'undefined' && define.amd) {
  1030. define([], function () {
  1031. return async;
  1032. });
  1033. }
  1034. // included directly via <script> tag
  1035. else {
  1036. root.async = async;
  1037. }
  1038. }());