No Description

async.js 34KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  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. for (var i = 0; i < arr.length; i += 1) {
  37. iterator(arr[i], i, arr);
  38. }
  39. };
  40. var _map = function (arr, iterator) {
  41. if (arr.map) {
  42. return arr.map(iterator);
  43. }
  44. var results = [];
  45. _each(arr, function (x, i, a) {
  46. results.push(iterator(x, i, a));
  47. });
  48. return results;
  49. };
  50. var _reduce = function (arr, iterator, memo) {
  51. if (arr.reduce) {
  52. return arr.reduce(iterator, memo);
  53. }
  54. _each(arr, function (x, i, a) {
  55. memo = iterator(memo, x, i, a);
  56. });
  57. return memo;
  58. };
  59. var _keys = function (obj) {
  60. if (Object.keys) {
  61. return Object.keys(obj);
  62. }
  63. var keys = [];
  64. for (var k in obj) {
  65. if (obj.hasOwnProperty(k)) {
  66. keys.push(k);
  67. }
  68. }
  69. return keys;
  70. };
  71. //// exported async module functions ////
  72. //// nextTick implementation with browser-compatible fallback ////
  73. if (typeof process === 'undefined' || !(process.nextTick)) {
  74. if (typeof setImmediate === 'function') {
  75. async.nextTick = function (fn) {
  76. // not a direct alias for IE10 compatibility
  77. setImmediate(fn);
  78. };
  79. async.setImmediate = async.nextTick;
  80. }
  81. else {
  82. async.nextTick = function (fn) {
  83. setTimeout(fn, 0);
  84. };
  85. async.setImmediate = async.nextTick;
  86. }
  87. }
  88. else {
  89. async.nextTick = process.nextTick;
  90. if (typeof setImmediate !== 'undefined') {
  91. async.setImmediate = function (fn) {
  92. // not a direct alias for IE10 compatibility
  93. setImmediate(fn);
  94. };
  95. }
  96. else {
  97. async.setImmediate = async.nextTick;
  98. }
  99. }
  100. async.each = function (arr, iterator, callback) {
  101. callback = callback || function () {};
  102. if (!arr.length) {
  103. return callback();
  104. }
  105. var completed = 0;
  106. _each(arr, function (x) {
  107. iterator(x, only_once(done) );
  108. });
  109. function done(err) {
  110. if (err) {
  111. callback(err);
  112. callback = function () {};
  113. }
  114. else {
  115. completed += 1;
  116. if (completed >= arr.length) {
  117. callback();
  118. }
  119. }
  120. }
  121. };
  122. async.forEach = async.each;
  123. async.eachSeries = function (arr, iterator, callback) {
  124. callback = callback || function () {};
  125. if (!arr.length) {
  126. return callback();
  127. }
  128. var completed = 0;
  129. var iterate = function () {
  130. iterator(arr[completed], function (err) {
  131. if (err) {
  132. callback(err);
  133. callback = function () {};
  134. }
  135. else {
  136. completed += 1;
  137. if (completed >= arr.length) {
  138. callback();
  139. }
  140. else {
  141. iterate();
  142. }
  143. }
  144. });
  145. };
  146. iterate();
  147. };
  148. async.forEachSeries = async.eachSeries;
  149. async.eachLimit = function (arr, limit, iterator, callback) {
  150. var fn = _eachLimit(limit);
  151. fn.apply(null, [arr, iterator, callback]);
  152. };
  153. async.forEachLimit = async.eachLimit;
  154. var _eachLimit = function (limit) {
  155. return function (arr, iterator, callback) {
  156. callback = callback || function () {};
  157. if (!arr.length || limit <= 0) {
  158. return callback();
  159. }
  160. var completed = 0;
  161. var started = 0;
  162. var running = 0;
  163. (function replenish () {
  164. if (completed >= arr.length) {
  165. return callback();
  166. }
  167. while (running < limit && started < arr.length) {
  168. started += 1;
  169. running += 1;
  170. iterator(arr[started - 1], function (err) {
  171. if (err) {
  172. callback(err);
  173. callback = function () {};
  174. }
  175. else {
  176. completed += 1;
  177. running -= 1;
  178. if (completed >= arr.length) {
  179. callback();
  180. }
  181. else {
  182. replenish();
  183. }
  184. }
  185. });
  186. }
  187. })();
  188. };
  189. };
  190. var doParallel = function (fn) {
  191. return function () {
  192. var args = Array.prototype.slice.call(arguments);
  193. return fn.apply(null, [async.each].concat(args));
  194. };
  195. };
  196. var doParallelLimit = function(limit, fn) {
  197. return function () {
  198. var args = Array.prototype.slice.call(arguments);
  199. return fn.apply(null, [_eachLimit(limit)].concat(args));
  200. };
  201. };
  202. var doSeries = function (fn) {
  203. return function () {
  204. var args = Array.prototype.slice.call(arguments);
  205. return fn.apply(null, [async.eachSeries].concat(args));
  206. };
  207. };
  208. var _asyncMap = function (eachfn, arr, iterator, callback) {
  209. arr = _map(arr, function (x, i) {
  210. return {index: i, value: x};
  211. });
  212. if (!callback) {
  213. eachfn(arr, function (x, callback) {
  214. iterator(x.value, function (err) {
  215. callback(err);
  216. });
  217. });
  218. } else {
  219. var results = [];
  220. eachfn(arr, function (x, callback) {
  221. iterator(x.value, function (err, v) {
  222. results[x.index] = v;
  223. callback(err);
  224. });
  225. }, function (err) {
  226. callback(err, results);
  227. });
  228. }
  229. };
  230. async.map = doParallel(_asyncMap);
  231. async.mapSeries = doSeries(_asyncMap);
  232. async.mapLimit = function (arr, limit, iterator, callback) {
  233. return _mapLimit(limit)(arr, iterator, callback);
  234. };
  235. var _mapLimit = function(limit) {
  236. return doParallelLimit(limit, _asyncMap);
  237. };
  238. // reduce only has a series version, as doing reduce in parallel won't
  239. // work in many situations.
  240. async.reduce = function (arr, memo, iterator, callback) {
  241. async.eachSeries(arr, function (x, callback) {
  242. iterator(memo, x, function (err, v) {
  243. memo = v;
  244. callback(err);
  245. });
  246. }, function (err) {
  247. callback(err, memo);
  248. });
  249. };
  250. // inject alias
  251. async.inject = async.reduce;
  252. // foldl alias
  253. async.foldl = async.reduce;
  254. async.reduceRight = function (arr, memo, iterator, callback) {
  255. var reversed = _map(arr, function (x) {
  256. return x;
  257. }).reverse();
  258. async.reduce(reversed, memo, iterator, callback);
  259. };
  260. // foldr alias
  261. async.foldr = async.reduceRight;
  262. var _filter = function (eachfn, arr, iterator, callback) {
  263. var results = [];
  264. arr = _map(arr, function (x, i) {
  265. return {index: i, value: x};
  266. });
  267. eachfn(arr, function (x, callback) {
  268. iterator(x.value, function (v) {
  269. if (v) {
  270. results.push(x);
  271. }
  272. callback();
  273. });
  274. }, function (err) {
  275. callback(_map(results.sort(function (a, b) {
  276. return a.index - b.index;
  277. }), function (x) {
  278. return x.value;
  279. }));
  280. });
  281. };
  282. async.filter = doParallel(_filter);
  283. async.filterSeries = doSeries(_filter);
  284. // select alias
  285. async.select = async.filter;
  286. async.selectSeries = async.filterSeries;
  287. var _reject = function (eachfn, arr, iterator, callback) {
  288. var results = [];
  289. arr = _map(arr, function (x, i) {
  290. return {index: i, value: x};
  291. });
  292. eachfn(arr, function (x, callback) {
  293. iterator(x.value, function (v) {
  294. if (!v) {
  295. results.push(x);
  296. }
  297. callback();
  298. });
  299. }, function (err) {
  300. callback(_map(results.sort(function (a, b) {
  301. return a.index - b.index;
  302. }), function (x) {
  303. return x.value;
  304. }));
  305. });
  306. };
  307. async.reject = doParallel(_reject);
  308. async.rejectSeries = doSeries(_reject);
  309. var _detect = function (eachfn, arr, iterator, main_callback) {
  310. eachfn(arr, function (x, callback) {
  311. iterator(x, function (result) {
  312. if (result) {
  313. main_callback(x);
  314. main_callback = function () {};
  315. }
  316. else {
  317. callback();
  318. }
  319. });
  320. }, function (err) {
  321. main_callback();
  322. });
  323. };
  324. async.detect = doParallel(_detect);
  325. async.detectSeries = doSeries(_detect);
  326. async.some = function (arr, iterator, main_callback) {
  327. async.each(arr, function (x, callback) {
  328. iterator(x, function (v) {
  329. if (v) {
  330. main_callback(true);
  331. main_callback = function () {};
  332. }
  333. callback();
  334. });
  335. }, function (err) {
  336. main_callback(false);
  337. });
  338. };
  339. // any alias
  340. async.any = async.some;
  341. async.every = function (arr, iterator, main_callback) {
  342. async.each(arr, function (x, callback) {
  343. iterator(x, function (v) {
  344. if (!v) {
  345. main_callback(false);
  346. main_callback = function () {};
  347. }
  348. callback();
  349. });
  350. }, function (err) {
  351. main_callback(true);
  352. });
  353. };
  354. // all alias
  355. async.all = async.every;
  356. async.sortBy = function (arr, iterator, callback) {
  357. async.map(arr, function (x, callback) {
  358. iterator(x, function (err, criteria) {
  359. if (err) {
  360. callback(err);
  361. }
  362. else {
  363. callback(null, {value: x, criteria: criteria});
  364. }
  365. });
  366. }, function (err, results) {
  367. if (err) {
  368. return callback(err);
  369. }
  370. else {
  371. var fn = function (left, right) {
  372. var a = left.criteria, b = right.criteria;
  373. return a < b ? -1 : a > b ? 1 : 0;
  374. };
  375. callback(null, _map(results.sort(fn), function (x) {
  376. return x.value;
  377. }));
  378. }
  379. });
  380. };
  381. async.auto = function (tasks, callback) {
  382. callback = callback || function () {};
  383. var keys = _keys(tasks);
  384. var remainingTasks = keys.length
  385. if (!remainingTasks) {
  386. return callback();
  387. }
  388. var results = {};
  389. var listeners = [];
  390. var addListener = function (fn) {
  391. listeners.unshift(fn);
  392. };
  393. var removeListener = function (fn) {
  394. for (var i = 0; i < listeners.length; i += 1) {
  395. if (listeners[i] === fn) {
  396. listeners.splice(i, 1);
  397. return;
  398. }
  399. }
  400. };
  401. var taskComplete = function () {
  402. remainingTasks--
  403. _each(listeners.slice(0), function (fn) {
  404. fn();
  405. });
  406. };
  407. addListener(function () {
  408. if (!remainingTasks) {
  409. var theCallback = callback;
  410. // prevent final callback from calling itself if it errors
  411. callback = function () {};
  412. theCallback(null, results);
  413. }
  414. });
  415. _each(keys, function (k) {
  416. var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
  417. var taskCallback = function (err) {
  418. var args = Array.prototype.slice.call(arguments, 1);
  419. if (args.length <= 1) {
  420. args = args[0];
  421. }
  422. if (err) {
  423. var safeResults = {};
  424. _each(_keys(results), function(rkey) {
  425. safeResults[rkey] = results[rkey];
  426. });
  427. safeResults[k] = args;
  428. callback(err, safeResults);
  429. // stop subsequent errors hitting callback multiple times
  430. callback = function () {};
  431. }
  432. else {
  433. results[k] = args;
  434. async.setImmediate(taskComplete);
  435. }
  436. };
  437. var requires = task.slice(0, Math.abs(task.length - 1)) || [];
  438. var ready = function () {
  439. return _reduce(requires, function (a, x) {
  440. return (a && results.hasOwnProperty(x));
  441. }, true) && !results.hasOwnProperty(k);
  442. };
  443. if (ready()) {
  444. task[task.length - 1](taskCallback, results);
  445. }
  446. else {
  447. var listener = function () {
  448. if (ready()) {
  449. removeListener(listener);
  450. task[task.length - 1](taskCallback, results);
  451. }
  452. };
  453. addListener(listener);
  454. }
  455. });
  456. };
  457. async.retry = function(times, task, callback) {
  458. var DEFAULT_TIMES = 5;
  459. var attempts = [];
  460. // Use defaults if times not passed
  461. if (typeof times === 'function') {
  462. callback = task;
  463. task = times;
  464. times = DEFAULT_TIMES;
  465. }
  466. // Make sure times is a number
  467. times = parseInt(times, 10) || DEFAULT_TIMES;
  468. var wrappedTask = function(wrappedCallback, wrappedResults) {
  469. var retryAttempt = function(task, finalAttempt) {
  470. return function(seriesCallback) {
  471. task(function(err, result){
  472. seriesCallback(!err || finalAttempt, {err: err, result: result});
  473. }, wrappedResults);
  474. };
  475. };
  476. while (times) {
  477. attempts.push(retryAttempt(task, !(times-=1)));
  478. }
  479. async.series(attempts, function(done, data){
  480. data = data[data.length - 1];
  481. (wrappedCallback || callback)(data.err, data.result);
  482. });
  483. }
  484. // If a callback is passed, run this as a controll flow
  485. return callback ? wrappedTask() : wrappedTask
  486. };
  487. async.waterfall = function (tasks, callback) {
  488. callback = callback || function () {};
  489. if (!_isArray(tasks)) {
  490. var err = new Error('First argument to waterfall must be an array of functions');
  491. return callback(err);
  492. }
  493. if (!tasks.length) {
  494. return callback();
  495. }
  496. var wrapIterator = function (iterator) {
  497. return function (err) {
  498. if (err) {
  499. callback.apply(null, arguments);
  500. callback = function () {};
  501. }
  502. else {
  503. var args = Array.prototype.slice.call(arguments, 1);
  504. var next = iterator.next();
  505. if (next) {
  506. args.push(wrapIterator(next));
  507. }
  508. else {
  509. args.push(callback);
  510. }
  511. async.setImmediate(function () {
  512. iterator.apply(null, args);
  513. });
  514. }
  515. };
  516. };
  517. wrapIterator(async.iterator(tasks))();
  518. };
  519. var _parallel = function(eachfn, tasks, callback) {
  520. callback = callback || function () {};
  521. if (_isArray(tasks)) {
  522. eachfn.map(tasks, function (fn, callback) {
  523. if (fn) {
  524. fn(function (err) {
  525. var args = Array.prototype.slice.call(arguments, 1);
  526. if (args.length <= 1) {
  527. args = args[0];
  528. }
  529. callback.call(null, err, args);
  530. });
  531. }
  532. }, callback);
  533. }
  534. else {
  535. var results = {};
  536. eachfn.each(_keys(tasks), function (k, callback) {
  537. tasks[k](function (err) {
  538. var args = Array.prototype.slice.call(arguments, 1);
  539. if (args.length <= 1) {
  540. args = args[0];
  541. }
  542. results[k] = args;
  543. callback(err);
  544. });
  545. }, function (err) {
  546. callback(err, results);
  547. });
  548. }
  549. };
  550. async.parallel = function (tasks, callback) {
  551. _parallel({ map: async.map, each: async.each }, tasks, callback);
  552. };
  553. async.parallelLimit = function(tasks, limit, callback) {
  554. _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);
  555. };
  556. async.series = function (tasks, callback) {
  557. callback = callback || function () {};
  558. if (_isArray(tasks)) {
  559. async.mapSeries(tasks, function (fn, callback) {
  560. if (fn) {
  561. fn(function (err) {
  562. var args = Array.prototype.slice.call(arguments, 1);
  563. if (args.length <= 1) {
  564. args = args[0];
  565. }
  566. callback.call(null, err, args);
  567. });
  568. }
  569. }, callback);
  570. }
  571. else {
  572. var results = {};
  573. async.eachSeries(_keys(tasks), function (k, callback) {
  574. tasks[k](function (err) {
  575. var args = Array.prototype.slice.call(arguments, 1);
  576. if (args.length <= 1) {
  577. args = args[0];
  578. }
  579. results[k] = args;
  580. callback(err);
  581. });
  582. }, function (err) {
  583. callback(err, results);
  584. });
  585. }
  586. };
  587. async.iterator = function (tasks) {
  588. var makeCallback = function (index) {
  589. var fn = function () {
  590. if (tasks.length) {
  591. tasks[index].apply(null, arguments);
  592. }
  593. return fn.next();
  594. };
  595. fn.next = function () {
  596. return (index < tasks.length - 1) ? makeCallback(index + 1): null;
  597. };
  598. return fn;
  599. };
  600. return makeCallback(0);
  601. };
  602. async.apply = function (fn) {
  603. var args = Array.prototype.slice.call(arguments, 1);
  604. return function () {
  605. return fn.apply(
  606. null, args.concat(Array.prototype.slice.call(arguments))
  607. );
  608. };
  609. };
  610. var _concat = function (eachfn, arr, fn, callback) {
  611. var r = [];
  612. eachfn(arr, function (x, cb) {
  613. fn(x, function (err, y) {
  614. r = r.concat(y || []);
  615. cb(err);
  616. });
  617. }, function (err) {
  618. callback(err, r);
  619. });
  620. };
  621. async.concat = doParallel(_concat);
  622. async.concatSeries = doSeries(_concat);
  623. async.whilst = function (test, iterator, callback) {
  624. if (test()) {
  625. iterator(function (err) {
  626. if (err) {
  627. return callback(err);
  628. }
  629. async.whilst(test, iterator, callback);
  630. });
  631. }
  632. else {
  633. callback();
  634. }
  635. };
  636. async.doWhilst = function (iterator, test, callback) {
  637. iterator(function (err) {
  638. if (err) {
  639. return callback(err);
  640. }
  641. var args = Array.prototype.slice.call(arguments, 1);
  642. if (test.apply(null, args)) {
  643. async.doWhilst(iterator, test, callback);
  644. }
  645. else {
  646. callback();
  647. }
  648. });
  649. };
  650. async.until = function (test, iterator, callback) {
  651. if (!test()) {
  652. iterator(function (err) {
  653. if (err) {
  654. return callback(err);
  655. }
  656. async.until(test, iterator, callback);
  657. });
  658. }
  659. else {
  660. callback();
  661. }
  662. };
  663. async.doUntil = function (iterator, test, callback) {
  664. iterator(function (err) {
  665. if (err) {
  666. return callback(err);
  667. }
  668. var args = Array.prototype.slice.call(arguments, 1);
  669. if (!test.apply(null, args)) {
  670. async.doUntil(iterator, test, callback);
  671. }
  672. else {
  673. callback();
  674. }
  675. });
  676. };
  677. async.queue = function (worker, concurrency) {
  678. if (concurrency === undefined) {
  679. concurrency = 1;
  680. }
  681. function _insert(q, data, pos, callback) {
  682. if (!q.started){
  683. q.started = true;
  684. }
  685. if (!_isArray(data)) {
  686. data = [data];
  687. }
  688. if(data.length == 0) {
  689. // call drain immediately if there are no tasks
  690. return async.setImmediate(function() {
  691. if (q.drain) {
  692. q.drain();
  693. }
  694. });
  695. }
  696. _each(data, function(task) {
  697. var item = {
  698. data: task,
  699. callback: typeof callback === 'function' ? callback : null
  700. };
  701. if (pos) {
  702. q.tasks.unshift(item);
  703. } else {
  704. q.tasks.push(item);
  705. }
  706. if (q.saturated && q.tasks.length === q.concurrency) {
  707. q.saturated();
  708. }
  709. async.setImmediate(q.process);
  710. });
  711. }
  712. var workers = 0;
  713. var q = {
  714. tasks: [],
  715. concurrency: concurrency,
  716. saturated: null,
  717. empty: null,
  718. drain: null,
  719. started: false,
  720. paused: false,
  721. push: function (data, callback) {
  722. _insert(q, data, false, callback);
  723. },
  724. kill: function () {
  725. q.drain = null;
  726. q.tasks = [];
  727. },
  728. unshift: function (data, callback) {
  729. _insert(q, data, true, callback);
  730. },
  731. process: function () {
  732. if (!q.paused && workers < q.concurrency && q.tasks.length) {
  733. var task = q.tasks.shift();
  734. if (q.empty && q.tasks.length === 0) {
  735. q.empty();
  736. }
  737. workers += 1;
  738. var next = function () {
  739. workers -= 1;
  740. if (task.callback) {
  741. task.callback.apply(task, arguments);
  742. }
  743. if (q.drain && q.tasks.length + workers === 0) {
  744. q.drain();
  745. }
  746. q.process();
  747. };
  748. var cb = only_once(next);
  749. worker(task.data, cb);
  750. }
  751. },
  752. length: function () {
  753. return q.tasks.length;
  754. },
  755. running: function () {
  756. return workers;
  757. },
  758. idle: function() {
  759. return q.tasks.length + workers === 0;
  760. },
  761. pause: function () {
  762. if (q.paused === true) { return; }
  763. q.paused = true;
  764. },
  765. resume: function () {
  766. if (q.paused === false) { return; }
  767. q.paused = false;
  768. // Need to call q.process once per concurrent
  769. // worker to preserve full concurrency after pause
  770. for (var w = 1; w <= q.concurrency; w++) {
  771. async.setImmediate(q.process);
  772. }
  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. }());