1 | (function (global, factory) {
|
---|
2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
---|
3 | typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
---|
4 | (factory((global.async = global.async || {})));
|
---|
5 | }(this, (function (exports) { 'use strict';
|
---|
6 |
|
---|
7 | function slice(arrayLike, start) {
|
---|
8 | start = start|0;
|
---|
9 | var newLen = Math.max(arrayLike.length - start, 0);
|
---|
10 | var newArr = Array(newLen);
|
---|
11 | for(var idx = 0; idx < newLen; idx++) {
|
---|
12 | newArr[idx] = arrayLike[start + idx];
|
---|
13 | }
|
---|
14 | return newArr;
|
---|
15 | }
|
---|
16 |
|
---|
17 | /**
|
---|
18 | * Creates a continuation function with some arguments already applied.
|
---|
19 | *
|
---|
20 | * Useful as a shorthand when combined with other control flow functions. Any
|
---|
21 | * arguments passed to the returned function are added to the arguments
|
---|
22 | * originally passed to apply.
|
---|
23 | *
|
---|
24 | * @name apply
|
---|
25 | * @static
|
---|
26 | * @memberOf module:Utils
|
---|
27 | * @method
|
---|
28 | * @category Util
|
---|
29 | * @param {Function} fn - The function you want to eventually apply all
|
---|
30 | * arguments to. Invokes with (arguments...).
|
---|
31 | * @param {...*} arguments... - Any number of arguments to automatically apply
|
---|
32 | * when the continuation is called.
|
---|
33 | * @returns {Function} the partially-applied function
|
---|
34 | * @example
|
---|
35 | *
|
---|
36 | * // using apply
|
---|
37 | * async.parallel([
|
---|
38 | * async.apply(fs.writeFile, 'testfile1', 'test1'),
|
---|
39 | * async.apply(fs.writeFile, 'testfile2', 'test2')
|
---|
40 | * ]);
|
---|
41 | *
|
---|
42 | *
|
---|
43 | * // the same process without using apply
|
---|
44 | * async.parallel([
|
---|
45 | * function(callback) {
|
---|
46 | * fs.writeFile('testfile1', 'test1', callback);
|
---|
47 | * },
|
---|
48 | * function(callback) {
|
---|
49 | * fs.writeFile('testfile2', 'test2', callback);
|
---|
50 | * }
|
---|
51 | * ]);
|
---|
52 | *
|
---|
53 | * // It's possible to pass any number of additional arguments when calling the
|
---|
54 | * // continuation:
|
---|
55 | *
|
---|
56 | * node> var fn = async.apply(sys.puts, 'one');
|
---|
57 | * node> fn('two', 'three');
|
---|
58 | * one
|
---|
59 | * two
|
---|
60 | * three
|
---|
61 | */
|
---|
62 | var apply = function(fn/*, ...args*/) {
|
---|
63 | var args = slice(arguments, 1);
|
---|
64 | return function(/*callArgs*/) {
|
---|
65 | var callArgs = slice(arguments);
|
---|
66 | return fn.apply(null, args.concat(callArgs));
|
---|
67 | };
|
---|
68 | };
|
---|
69 |
|
---|
70 | var initialParams = function (fn) {
|
---|
71 | return function (/*...args, callback*/) {
|
---|
72 | var args = slice(arguments);
|
---|
73 | var callback = args.pop();
|
---|
74 | fn.call(this, args, callback);
|
---|
75 | };
|
---|
76 | };
|
---|
77 |
|
---|
78 | /**
|
---|
79 | * Checks if `value` is the
|
---|
80 | * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
|
---|
81 | * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
---|
82 | *
|
---|
83 | * @static
|
---|
84 | * @memberOf _
|
---|
85 | * @since 0.1.0
|
---|
86 | * @category Lang
|
---|
87 | * @param {*} value The value to check.
|
---|
88 | * @returns {boolean} Returns `true` if `value` is an object, else `false`.
|
---|
89 | * @example
|
---|
90 | *
|
---|
91 | * _.isObject({});
|
---|
92 | * // => true
|
---|
93 | *
|
---|
94 | * _.isObject([1, 2, 3]);
|
---|
95 | * // => true
|
---|
96 | *
|
---|
97 | * _.isObject(_.noop);
|
---|
98 | * // => true
|
---|
99 | *
|
---|
100 | * _.isObject(null);
|
---|
101 | * // => false
|
---|
102 | */
|
---|
103 | function isObject(value) {
|
---|
104 | var type = typeof value;
|
---|
105 | return value != null && (type == 'object' || type == 'function');
|
---|
106 | }
|
---|
107 |
|
---|
108 | var hasSetImmediate = typeof setImmediate === 'function' && setImmediate;
|
---|
109 | var hasNextTick = typeof process === 'object' && typeof process.nextTick === 'function';
|
---|
110 |
|
---|
111 | function fallback(fn) {
|
---|
112 | setTimeout(fn, 0);
|
---|
113 | }
|
---|
114 |
|
---|
115 | function wrap(defer) {
|
---|
116 | return function (fn/*, ...args*/) {
|
---|
117 | var args = slice(arguments, 1);
|
---|
118 | defer(function () {
|
---|
119 | fn.apply(null, args);
|
---|
120 | });
|
---|
121 | };
|
---|
122 | }
|
---|
123 |
|
---|
124 | var _defer;
|
---|
125 |
|
---|
126 | if (hasSetImmediate) {
|
---|
127 | _defer = setImmediate;
|
---|
128 | } else if (hasNextTick) {
|
---|
129 | _defer = process.nextTick;
|
---|
130 | } else {
|
---|
131 | _defer = fallback;
|
---|
132 | }
|
---|
133 |
|
---|
134 | var setImmediate$1 = wrap(_defer);
|
---|
135 |
|
---|
136 | /**
|
---|
137 | * Take a sync function and make it async, passing its return value to a
|
---|
138 | * callback. This is useful for plugging sync functions into a waterfall,
|
---|
139 | * series, or other async functions. Any arguments passed to the generated
|
---|
140 | * function will be passed to the wrapped function (except for the final
|
---|
141 | * callback argument). Errors thrown will be passed to the callback.
|
---|
142 | *
|
---|
143 | * If the function passed to `asyncify` returns a Promise, that promises's
|
---|
144 | * resolved/rejected state will be used to call the callback, rather than simply
|
---|
145 | * the synchronous return value.
|
---|
146 | *
|
---|
147 | * This also means you can asyncify ES2017 `async` functions.
|
---|
148 | *
|
---|
149 | * @name asyncify
|
---|
150 | * @static
|
---|
151 | * @memberOf module:Utils
|
---|
152 | * @method
|
---|
153 | * @alias wrapSync
|
---|
154 | * @category Util
|
---|
155 | * @param {Function} func - The synchronous function, or Promise-returning
|
---|
156 | * function to convert to an {@link AsyncFunction}.
|
---|
157 | * @returns {AsyncFunction} An asynchronous wrapper of the `func`. To be
|
---|
158 | * invoked with `(args..., callback)`.
|
---|
159 | * @example
|
---|
160 | *
|
---|
161 | * // passing a regular synchronous function
|
---|
162 | * async.waterfall([
|
---|
163 | * async.apply(fs.readFile, filename, "utf8"),
|
---|
164 | * async.asyncify(JSON.parse),
|
---|
165 | * function (data, next) {
|
---|
166 | * // data is the result of parsing the text.
|
---|
167 | * // If there was a parsing error, it would have been caught.
|
---|
168 | * }
|
---|
169 | * ], callback);
|
---|
170 | *
|
---|
171 | * // passing a function returning a promise
|
---|
172 | * async.waterfall([
|
---|
173 | * async.apply(fs.readFile, filename, "utf8"),
|
---|
174 | * async.asyncify(function (contents) {
|
---|
175 | * return db.model.create(contents);
|
---|
176 | * }),
|
---|
177 | * function (model, next) {
|
---|
178 | * // `model` is the instantiated model object.
|
---|
179 | * // If there was an error, this function would be skipped.
|
---|
180 | * }
|
---|
181 | * ], callback);
|
---|
182 | *
|
---|
183 | * // es2017 example, though `asyncify` is not needed if your JS environment
|
---|
184 | * // supports async functions out of the box
|
---|
185 | * var q = async.queue(async.asyncify(async function(file) {
|
---|
186 | * var intermediateStep = await processFile(file);
|
---|
187 | * return await somePromise(intermediateStep)
|
---|
188 | * }));
|
---|
189 | *
|
---|
190 | * q.push(files);
|
---|
191 | */
|
---|
192 | function asyncify(func) {
|
---|
193 | return initialParams(function (args, callback) {
|
---|
194 | var result;
|
---|
195 | try {
|
---|
196 | result = func.apply(this, args);
|
---|
197 | } catch (e) {
|
---|
198 | return callback(e);
|
---|
199 | }
|
---|
200 | // if result is Promise object
|
---|
201 | if (isObject(result) && typeof result.then === 'function') {
|
---|
202 | result.then(function(value) {
|
---|
203 | invokeCallback(callback, null, value);
|
---|
204 | }, function(err) {
|
---|
205 | invokeCallback(callback, err.message ? err : new Error(err));
|
---|
206 | });
|
---|
207 | } else {
|
---|
208 | callback(null, result);
|
---|
209 | }
|
---|
210 | });
|
---|
211 | }
|
---|
212 |
|
---|
213 | function invokeCallback(callback, error, value) {
|
---|
214 | try {
|
---|
215 | callback(error, value);
|
---|
216 | } catch (e) {
|
---|
217 | setImmediate$1(rethrow, e);
|
---|
218 | }
|
---|
219 | }
|
---|
220 |
|
---|
221 | function rethrow(error) {
|
---|
222 | throw error;
|
---|
223 | }
|
---|
224 |
|
---|
225 | var supportsSymbol = typeof Symbol === 'function';
|
---|
226 |
|
---|
227 | function isAsync(fn) {
|
---|
228 | return supportsSymbol && fn[Symbol.toStringTag] === 'AsyncFunction';
|
---|
229 | }
|
---|
230 |
|
---|
231 | function wrapAsync(asyncFn) {
|
---|
232 | return isAsync(asyncFn) ? asyncify(asyncFn) : asyncFn;
|
---|
233 | }
|
---|
234 |
|
---|
235 | function applyEach$1(eachfn) {
|
---|
236 | return function(fns/*, ...args*/) {
|
---|
237 | var args = slice(arguments, 1);
|
---|
238 | var go = initialParams(function(args, callback) {
|
---|
239 | var that = this;
|
---|
240 | return eachfn(fns, function (fn, cb) {
|
---|
241 | wrapAsync(fn).apply(that, args.concat(cb));
|
---|
242 | }, callback);
|
---|
243 | });
|
---|
244 | if (args.length) {
|
---|
245 | return go.apply(this, args);
|
---|
246 | }
|
---|
247 | else {
|
---|
248 | return go;
|
---|
249 | }
|
---|
250 | };
|
---|
251 | }
|
---|
252 |
|
---|
253 | /** Detect free variable `global` from Node.js. */
|
---|
254 | var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
|
---|
255 |
|
---|
256 | /** Detect free variable `self`. */
|
---|
257 | var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
|
---|
258 |
|
---|
259 | /** Used as a reference to the global object. */
|
---|
260 | var root = freeGlobal || freeSelf || Function('return this')();
|
---|
261 |
|
---|
262 | /** Built-in value references. */
|
---|
263 | var Symbol$1 = root.Symbol;
|
---|
264 |
|
---|
265 | /** Used for built-in method references. */
|
---|
266 | var objectProto = Object.prototype;
|
---|
267 |
|
---|
268 | /** Used to check objects for own properties. */
|
---|
269 | var hasOwnProperty = objectProto.hasOwnProperty;
|
---|
270 |
|
---|
271 | /**
|
---|
272 | * Used to resolve the
|
---|
273 | * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
|
---|
274 | * of values.
|
---|
275 | */
|
---|
276 | var nativeObjectToString = objectProto.toString;
|
---|
277 |
|
---|
278 | /** Built-in value references. */
|
---|
279 | var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined;
|
---|
280 |
|
---|
281 | /**
|
---|
282 | * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
|
---|
283 | *
|
---|
284 | * @private
|
---|
285 | * @param {*} value The value to query.
|
---|
286 | * @returns {string} Returns the raw `toStringTag`.
|
---|
287 | */
|
---|
288 | function getRawTag(value) {
|
---|
289 | var isOwn = hasOwnProperty.call(value, symToStringTag$1),
|
---|
290 | tag = value[symToStringTag$1];
|
---|
291 |
|
---|
292 | try {
|
---|
293 | value[symToStringTag$1] = undefined;
|
---|
294 | var unmasked = true;
|
---|
295 | } catch (e) {}
|
---|
296 |
|
---|
297 | var result = nativeObjectToString.call(value);
|
---|
298 | if (unmasked) {
|
---|
299 | if (isOwn) {
|
---|
300 | value[symToStringTag$1] = tag;
|
---|
301 | } else {
|
---|
302 | delete value[symToStringTag$1];
|
---|
303 | }
|
---|
304 | }
|
---|
305 | return result;
|
---|
306 | }
|
---|
307 |
|
---|
308 | /** Used for built-in method references. */
|
---|
309 | var objectProto$1 = Object.prototype;
|
---|
310 |
|
---|
311 | /**
|
---|
312 | * Used to resolve the
|
---|
313 | * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
|
---|
314 | * of values.
|
---|
315 | */
|
---|
316 | var nativeObjectToString$1 = objectProto$1.toString;
|
---|
317 |
|
---|
318 | /**
|
---|
319 | * Converts `value` to a string using `Object.prototype.toString`.
|
---|
320 | *
|
---|
321 | * @private
|
---|
322 | * @param {*} value The value to convert.
|
---|
323 | * @returns {string} Returns the converted string.
|
---|
324 | */
|
---|
325 | function objectToString(value) {
|
---|
326 | return nativeObjectToString$1.call(value);
|
---|
327 | }
|
---|
328 |
|
---|
329 | /** `Object#toString` result references. */
|
---|
330 | var nullTag = '[object Null]';
|
---|
331 | var undefinedTag = '[object Undefined]';
|
---|
332 |
|
---|
333 | /** Built-in value references. */
|
---|
334 | var symToStringTag = Symbol$1 ? Symbol$1.toStringTag : undefined;
|
---|
335 |
|
---|
336 | /**
|
---|
337 | * The base implementation of `getTag` without fallbacks for buggy environments.
|
---|
338 | *
|
---|
339 | * @private
|
---|
340 | * @param {*} value The value to query.
|
---|
341 | * @returns {string} Returns the `toStringTag`.
|
---|
342 | */
|
---|
343 | function baseGetTag(value) {
|
---|
344 | if (value == null) {
|
---|
345 | return value === undefined ? undefinedTag : nullTag;
|
---|
346 | }
|
---|
347 | return (symToStringTag && symToStringTag in Object(value))
|
---|
348 | ? getRawTag(value)
|
---|
349 | : objectToString(value);
|
---|
350 | }
|
---|
351 |
|
---|
352 | /** `Object#toString` result references. */
|
---|
353 | var asyncTag = '[object AsyncFunction]';
|
---|
354 | var funcTag = '[object Function]';
|
---|
355 | var genTag = '[object GeneratorFunction]';
|
---|
356 | var proxyTag = '[object Proxy]';
|
---|
357 |
|
---|
358 | /**
|
---|
359 | * Checks if `value` is classified as a `Function` object.
|
---|
360 | *
|
---|
361 | * @static
|
---|
362 | * @memberOf _
|
---|
363 | * @since 0.1.0
|
---|
364 | * @category Lang
|
---|
365 | * @param {*} value The value to check.
|
---|
366 | * @returns {boolean} Returns `true` if `value` is a function, else `false`.
|
---|
367 | * @example
|
---|
368 | *
|
---|
369 | * _.isFunction(_);
|
---|
370 | * // => true
|
---|
371 | *
|
---|
372 | * _.isFunction(/abc/);
|
---|
373 | * // => false
|
---|
374 | */
|
---|
375 | function isFunction(value) {
|
---|
376 | if (!isObject(value)) {
|
---|
377 | return false;
|
---|
378 | }
|
---|
379 | // The use of `Object#toString` avoids issues with the `typeof` operator
|
---|
380 | // in Safari 9 which returns 'object' for typed arrays and other constructors.
|
---|
381 | var tag = baseGetTag(value);
|
---|
382 | return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
|
---|
383 | }
|
---|
384 |
|
---|
385 | /** Used as references for various `Number` constants. */
|
---|
386 | var MAX_SAFE_INTEGER = 9007199254740991;
|
---|
387 |
|
---|
388 | /**
|
---|
389 | * Checks if `value` is a valid array-like length.
|
---|
390 | *
|
---|
391 | * **Note:** This method is loosely based on
|
---|
392 | * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
|
---|
393 | *
|
---|
394 | * @static
|
---|
395 | * @memberOf _
|
---|
396 | * @since 4.0.0
|
---|
397 | * @category Lang
|
---|
398 | * @param {*} value The value to check.
|
---|
399 | * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
|
---|
400 | * @example
|
---|
401 | *
|
---|
402 | * _.isLength(3);
|
---|
403 | * // => true
|
---|
404 | *
|
---|
405 | * _.isLength(Number.MIN_VALUE);
|
---|
406 | * // => false
|
---|
407 | *
|
---|
408 | * _.isLength(Infinity);
|
---|
409 | * // => false
|
---|
410 | *
|
---|
411 | * _.isLength('3');
|
---|
412 | * // => false
|
---|
413 | */
|
---|
414 | function isLength(value) {
|
---|
415 | return typeof value == 'number' &&
|
---|
416 | value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
|
---|
417 | }
|
---|
418 |
|
---|
419 | /**
|
---|
420 | * Checks if `value` is array-like. A value is considered array-like if it's
|
---|
421 | * not a function and has a `value.length` that's an integer greater than or
|
---|
422 | * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
|
---|
423 | *
|
---|
424 | * @static
|
---|
425 | * @memberOf _
|
---|
426 | * @since 4.0.0
|
---|
427 | * @category Lang
|
---|
428 | * @param {*} value The value to check.
|
---|
429 | * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
|
---|
430 | * @example
|
---|
431 | *
|
---|
432 | * _.isArrayLike([1, 2, 3]);
|
---|
433 | * // => true
|
---|
434 | *
|
---|
435 | * _.isArrayLike(document.body.children);
|
---|
436 | * // => true
|
---|
437 | *
|
---|
438 | * _.isArrayLike('abc');
|
---|
439 | * // => true
|
---|
440 | *
|
---|
441 | * _.isArrayLike(_.noop);
|
---|
442 | * // => false
|
---|
443 | */
|
---|
444 | function isArrayLike(value) {
|
---|
445 | return value != null && isLength(value.length) && !isFunction(value);
|
---|
446 | }
|
---|
447 |
|
---|
448 | // A temporary value used to identify if the loop should be broken.
|
---|
449 | // See #1064, #1293
|
---|
450 | var breakLoop = {};
|
---|
451 |
|
---|
452 | /**
|
---|
453 | * This method returns `undefined`.
|
---|
454 | *
|
---|
455 | * @static
|
---|
456 | * @memberOf _
|
---|
457 | * @since 2.3.0
|
---|
458 | * @category Util
|
---|
459 | * @example
|
---|
460 | *
|
---|
461 | * _.times(2, _.noop);
|
---|
462 | * // => [undefined, undefined]
|
---|
463 | */
|
---|
464 | function noop() {
|
---|
465 | // No operation performed.
|
---|
466 | }
|
---|
467 |
|
---|
468 | function once(fn) {
|
---|
469 | return function () {
|
---|
470 | if (fn === null) return;
|
---|
471 | var callFn = fn;
|
---|
472 | fn = null;
|
---|
473 | callFn.apply(this, arguments);
|
---|
474 | };
|
---|
475 | }
|
---|
476 |
|
---|
477 | var iteratorSymbol = typeof Symbol === 'function' && Symbol.iterator;
|
---|
478 |
|
---|
479 | var getIterator = function (coll) {
|
---|
480 | return iteratorSymbol && coll[iteratorSymbol] && coll[iteratorSymbol]();
|
---|
481 | };
|
---|
482 |
|
---|
483 | /**
|
---|
484 | * The base implementation of `_.times` without support for iteratee shorthands
|
---|
485 | * or max array length checks.
|
---|
486 | *
|
---|
487 | * @private
|
---|
488 | * @param {number} n The number of times to invoke `iteratee`.
|
---|
489 | * @param {Function} iteratee The function invoked per iteration.
|
---|
490 | * @returns {Array} Returns the array of results.
|
---|
491 | */
|
---|
492 | function baseTimes(n, iteratee) {
|
---|
493 | var index = -1,
|
---|
494 | result = Array(n);
|
---|
495 |
|
---|
496 | while (++index < n) {
|
---|
497 | result[index] = iteratee(index);
|
---|
498 | }
|
---|
499 | return result;
|
---|
500 | }
|
---|
501 |
|
---|
502 | /**
|
---|
503 | * Checks if `value` is object-like. A value is object-like if it's not `null`
|
---|
504 | * and has a `typeof` result of "object".
|
---|
505 | *
|
---|
506 | * @static
|
---|
507 | * @memberOf _
|
---|
508 | * @since 4.0.0
|
---|
509 | * @category Lang
|
---|
510 | * @param {*} value The value to check.
|
---|
511 | * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
|
---|
512 | * @example
|
---|
513 | *
|
---|
514 | * _.isObjectLike({});
|
---|
515 | * // => true
|
---|
516 | *
|
---|
517 | * _.isObjectLike([1, 2, 3]);
|
---|
518 | * // => true
|
---|
519 | *
|
---|
520 | * _.isObjectLike(_.noop);
|
---|
521 | * // => false
|
---|
522 | *
|
---|
523 | * _.isObjectLike(null);
|
---|
524 | * // => false
|
---|
525 | */
|
---|
526 | function isObjectLike(value) {
|
---|
527 | return value != null && typeof value == 'object';
|
---|
528 | }
|
---|
529 |
|
---|
530 | /** `Object#toString` result references. */
|
---|
531 | var argsTag = '[object Arguments]';
|
---|
532 |
|
---|
533 | /**
|
---|
534 | * The base implementation of `_.isArguments`.
|
---|
535 | *
|
---|
536 | * @private
|
---|
537 | * @param {*} value The value to check.
|
---|
538 | * @returns {boolean} Returns `true` if `value` is an `arguments` object,
|
---|
539 | */
|
---|
540 | function baseIsArguments(value) {
|
---|
541 | return isObjectLike(value) && baseGetTag(value) == argsTag;
|
---|
542 | }
|
---|
543 |
|
---|
544 | /** Used for built-in method references. */
|
---|
545 | var objectProto$3 = Object.prototype;
|
---|
546 |
|
---|
547 | /** Used to check objects for own properties. */
|
---|
548 | var hasOwnProperty$2 = objectProto$3.hasOwnProperty;
|
---|
549 |
|
---|
550 | /** Built-in value references. */
|
---|
551 | var propertyIsEnumerable = objectProto$3.propertyIsEnumerable;
|
---|
552 |
|
---|
553 | /**
|
---|
554 | * Checks if `value` is likely an `arguments` object.
|
---|
555 | *
|
---|
556 | * @static
|
---|
557 | * @memberOf _
|
---|
558 | * @since 0.1.0
|
---|
559 | * @category Lang
|
---|
560 | * @param {*} value The value to check.
|
---|
561 | * @returns {boolean} Returns `true` if `value` is an `arguments` object,
|
---|
562 | * else `false`.
|
---|
563 | * @example
|
---|
564 | *
|
---|
565 | * _.isArguments(function() { return arguments; }());
|
---|
566 | * // => true
|
---|
567 | *
|
---|
568 | * _.isArguments([1, 2, 3]);
|
---|
569 | * // => false
|
---|
570 | */
|
---|
571 | var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
|
---|
572 | return isObjectLike(value) && hasOwnProperty$2.call(value, 'callee') &&
|
---|
573 | !propertyIsEnumerable.call(value, 'callee');
|
---|
574 | };
|
---|
575 |
|
---|
576 | /**
|
---|
577 | * Checks if `value` is classified as an `Array` object.
|
---|
578 | *
|
---|
579 | * @static
|
---|
580 | * @memberOf _
|
---|
581 | * @since 0.1.0
|
---|
582 | * @category Lang
|
---|
583 | * @param {*} value The value to check.
|
---|
584 | * @returns {boolean} Returns `true` if `value` is an array, else `false`.
|
---|
585 | * @example
|
---|
586 | *
|
---|
587 | * _.isArray([1, 2, 3]);
|
---|
588 | * // => true
|
---|
589 | *
|
---|
590 | * _.isArray(document.body.children);
|
---|
591 | * // => false
|
---|
592 | *
|
---|
593 | * _.isArray('abc');
|
---|
594 | * // => false
|
---|
595 | *
|
---|
596 | * _.isArray(_.noop);
|
---|
597 | * // => false
|
---|
598 | */
|
---|
599 | var isArray = Array.isArray;
|
---|
600 |
|
---|
601 | /**
|
---|
602 | * This method returns `false`.
|
---|
603 | *
|
---|
604 | * @static
|
---|
605 | * @memberOf _
|
---|
606 | * @since 4.13.0
|
---|
607 | * @category Util
|
---|
608 | * @returns {boolean} Returns `false`.
|
---|
609 | * @example
|
---|
610 | *
|
---|
611 | * _.times(2, _.stubFalse);
|
---|
612 | * // => [false, false]
|
---|
613 | */
|
---|
614 | function stubFalse() {
|
---|
615 | return false;
|
---|
616 | }
|
---|
617 |
|
---|
618 | /** Detect free variable `exports`. */
|
---|
619 | var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
|
---|
620 |
|
---|
621 | /** Detect free variable `module`. */
|
---|
622 | var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
|
---|
623 |
|
---|
624 | /** Detect the popular CommonJS extension `module.exports`. */
|
---|
625 | var moduleExports = freeModule && freeModule.exports === freeExports;
|
---|
626 |
|
---|
627 | /** Built-in value references. */
|
---|
628 | var Buffer = moduleExports ? root.Buffer : undefined;
|
---|
629 |
|
---|
630 | /* Built-in method references for those with the same name as other `lodash` methods. */
|
---|
631 | var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined;
|
---|
632 |
|
---|
633 | /**
|
---|
634 | * Checks if `value` is a buffer.
|
---|
635 | *
|
---|
636 | * @static
|
---|
637 | * @memberOf _
|
---|
638 | * @since 4.3.0
|
---|
639 | * @category Lang
|
---|
640 | * @param {*} value The value to check.
|
---|
641 | * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
|
---|
642 | * @example
|
---|
643 | *
|
---|
644 | * _.isBuffer(new Buffer(2));
|
---|
645 | * // => true
|
---|
646 | *
|
---|
647 | * _.isBuffer(new Uint8Array(2));
|
---|
648 | * // => false
|
---|
649 | */
|
---|
650 | var isBuffer = nativeIsBuffer || stubFalse;
|
---|
651 |
|
---|
652 | /** Used as references for various `Number` constants. */
|
---|
653 | var MAX_SAFE_INTEGER$1 = 9007199254740991;
|
---|
654 |
|
---|
655 | /** Used to detect unsigned integer values. */
|
---|
656 | var reIsUint = /^(?:0|[1-9]\d*)$/;
|
---|
657 |
|
---|
658 | /**
|
---|
659 | * Checks if `value` is a valid array-like index.
|
---|
660 | *
|
---|
661 | * @private
|
---|
662 | * @param {*} value The value to check.
|
---|
663 | * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
|
---|
664 | * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
|
---|
665 | */
|
---|
666 | function isIndex(value, length) {
|
---|
667 | var type = typeof value;
|
---|
668 | length = length == null ? MAX_SAFE_INTEGER$1 : length;
|
---|
669 |
|
---|
670 | return !!length &&
|
---|
671 | (type == 'number' ||
|
---|
672 | (type != 'symbol' && reIsUint.test(value))) &&
|
---|
673 | (value > -1 && value % 1 == 0 && value < length);
|
---|
674 | }
|
---|
675 |
|
---|
676 | /** `Object#toString` result references. */
|
---|
677 | var argsTag$1 = '[object Arguments]';
|
---|
678 | var arrayTag = '[object Array]';
|
---|
679 | var boolTag = '[object Boolean]';
|
---|
680 | var dateTag = '[object Date]';
|
---|
681 | var errorTag = '[object Error]';
|
---|
682 | var funcTag$1 = '[object Function]';
|
---|
683 | var mapTag = '[object Map]';
|
---|
684 | var numberTag = '[object Number]';
|
---|
685 | var objectTag = '[object Object]';
|
---|
686 | var regexpTag = '[object RegExp]';
|
---|
687 | var setTag = '[object Set]';
|
---|
688 | var stringTag = '[object String]';
|
---|
689 | var weakMapTag = '[object WeakMap]';
|
---|
690 |
|
---|
691 | var arrayBufferTag = '[object ArrayBuffer]';
|
---|
692 | var dataViewTag = '[object DataView]';
|
---|
693 | var float32Tag = '[object Float32Array]';
|
---|
694 | var float64Tag = '[object Float64Array]';
|
---|
695 | var int8Tag = '[object Int8Array]';
|
---|
696 | var int16Tag = '[object Int16Array]';
|
---|
697 | var int32Tag = '[object Int32Array]';
|
---|
698 | var uint8Tag = '[object Uint8Array]';
|
---|
699 | var uint8ClampedTag = '[object Uint8ClampedArray]';
|
---|
700 | var uint16Tag = '[object Uint16Array]';
|
---|
701 | var uint32Tag = '[object Uint32Array]';
|
---|
702 |
|
---|
703 | /** Used to identify `toStringTag` values of typed arrays. */
|
---|
704 | var typedArrayTags = {};
|
---|
705 | typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
|
---|
706 | typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
|
---|
707 | typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
|
---|
708 | typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
|
---|
709 | typedArrayTags[uint32Tag] = true;
|
---|
710 | typedArrayTags[argsTag$1] = typedArrayTags[arrayTag] =
|
---|
711 | typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
|
---|
712 | typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
|
---|
713 | typedArrayTags[errorTag] = typedArrayTags[funcTag$1] =
|
---|
714 | typedArrayTags[mapTag] = typedArrayTags[numberTag] =
|
---|
715 | typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
|
---|
716 | typedArrayTags[setTag] = typedArrayTags[stringTag] =
|
---|
717 | typedArrayTags[weakMapTag] = false;
|
---|
718 |
|
---|
719 | /**
|
---|
720 | * The base implementation of `_.isTypedArray` without Node.js optimizations.
|
---|
721 | *
|
---|
722 | * @private
|
---|
723 | * @param {*} value The value to check.
|
---|
724 | * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
|
---|
725 | */
|
---|
726 | function baseIsTypedArray(value) {
|
---|
727 | return isObjectLike(value) &&
|
---|
728 | isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
|
---|
729 | }
|
---|
730 |
|
---|
731 | /**
|
---|
732 | * The base implementation of `_.unary` without support for storing metadata.
|
---|
733 | *
|
---|
734 | * @private
|
---|
735 | * @param {Function} func The function to cap arguments for.
|
---|
736 | * @returns {Function} Returns the new capped function.
|
---|
737 | */
|
---|
738 | function baseUnary(func) {
|
---|
739 | return function(value) {
|
---|
740 | return func(value);
|
---|
741 | };
|
---|
742 | }
|
---|
743 |
|
---|
744 | /** Detect free variable `exports`. */
|
---|
745 | var freeExports$1 = typeof exports == 'object' && exports && !exports.nodeType && exports;
|
---|
746 |
|
---|
747 | /** Detect free variable `module`. */
|
---|
748 | var freeModule$1 = freeExports$1 && typeof module == 'object' && module && !module.nodeType && module;
|
---|
749 |
|
---|
750 | /** Detect the popular CommonJS extension `module.exports`. */
|
---|
751 | var moduleExports$1 = freeModule$1 && freeModule$1.exports === freeExports$1;
|
---|
752 |
|
---|
753 | /** Detect free variable `process` from Node.js. */
|
---|
754 | var freeProcess = moduleExports$1 && freeGlobal.process;
|
---|
755 |
|
---|
756 | /** Used to access faster Node.js helpers. */
|
---|
757 | var nodeUtil = (function() {
|
---|
758 | try {
|
---|
759 | // Use `util.types` for Node.js 10+.
|
---|
760 | var types = freeModule$1 && freeModule$1.require && freeModule$1.require('util').types;
|
---|
761 |
|
---|
762 | if (types) {
|
---|
763 | return types;
|
---|
764 | }
|
---|
765 |
|
---|
766 | // Legacy `process.binding('util')` for Node.js < 10.
|
---|
767 | return freeProcess && freeProcess.binding && freeProcess.binding('util');
|
---|
768 | } catch (e) {}
|
---|
769 | }());
|
---|
770 |
|
---|
771 | /* Node.js helper references. */
|
---|
772 | var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
|
---|
773 |
|
---|
774 | /**
|
---|
775 | * Checks if `value` is classified as a typed array.
|
---|
776 | *
|
---|
777 | * @static
|
---|
778 | * @memberOf _
|
---|
779 | * @since 3.0.0
|
---|
780 | * @category Lang
|
---|
781 | * @param {*} value The value to check.
|
---|
782 | * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
|
---|
783 | * @example
|
---|
784 | *
|
---|
785 | * _.isTypedArray(new Uint8Array);
|
---|
786 | * // => true
|
---|
787 | *
|
---|
788 | * _.isTypedArray([]);
|
---|
789 | * // => false
|
---|
790 | */
|
---|
791 | var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
|
---|
792 |
|
---|
793 | /** Used for built-in method references. */
|
---|
794 | var objectProto$2 = Object.prototype;
|
---|
795 |
|
---|
796 | /** Used to check objects for own properties. */
|
---|
797 | var hasOwnProperty$1 = objectProto$2.hasOwnProperty;
|
---|
798 |
|
---|
799 | /**
|
---|
800 | * Creates an array of the enumerable property names of the array-like `value`.
|
---|
801 | *
|
---|
802 | * @private
|
---|
803 | * @param {*} value The value to query.
|
---|
804 | * @param {boolean} inherited Specify returning inherited property names.
|
---|
805 | * @returns {Array} Returns the array of property names.
|
---|
806 | */
|
---|
807 | function arrayLikeKeys(value, inherited) {
|
---|
808 | var isArr = isArray(value),
|
---|
809 | isArg = !isArr && isArguments(value),
|
---|
810 | isBuff = !isArr && !isArg && isBuffer(value),
|
---|
811 | isType = !isArr && !isArg && !isBuff && isTypedArray(value),
|
---|
812 | skipIndexes = isArr || isArg || isBuff || isType,
|
---|
813 | result = skipIndexes ? baseTimes(value.length, String) : [],
|
---|
814 | length = result.length;
|
---|
815 |
|
---|
816 | for (var key in value) {
|
---|
817 | if ((inherited || hasOwnProperty$1.call(value, key)) &&
|
---|
818 | !(skipIndexes && (
|
---|
819 | // Safari 9 has enumerable `arguments.length` in strict mode.
|
---|
820 | key == 'length' ||
|
---|
821 | // Node.js 0.10 has enumerable non-index properties on buffers.
|
---|
822 | (isBuff && (key == 'offset' || key == 'parent')) ||
|
---|
823 | // PhantomJS 2 has enumerable non-index properties on typed arrays.
|
---|
824 | (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
|
---|
825 | // Skip index properties.
|
---|
826 | isIndex(key, length)
|
---|
827 | ))) {
|
---|
828 | result.push(key);
|
---|
829 | }
|
---|
830 | }
|
---|
831 | return result;
|
---|
832 | }
|
---|
833 |
|
---|
834 | /** Used for built-in method references. */
|
---|
835 | var objectProto$5 = Object.prototype;
|
---|
836 |
|
---|
837 | /**
|
---|
838 | * Checks if `value` is likely a prototype object.
|
---|
839 | *
|
---|
840 | * @private
|
---|
841 | * @param {*} value The value to check.
|
---|
842 | * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
|
---|
843 | */
|
---|
844 | function isPrototype(value) {
|
---|
845 | var Ctor = value && value.constructor,
|
---|
846 | proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto$5;
|
---|
847 |
|
---|
848 | return value === proto;
|
---|
849 | }
|
---|
850 |
|
---|
851 | /**
|
---|
852 | * Creates a unary function that invokes `func` with its argument transformed.
|
---|
853 | *
|
---|
854 | * @private
|
---|
855 | * @param {Function} func The function to wrap.
|
---|
856 | * @param {Function} transform The argument transform.
|
---|
857 | * @returns {Function} Returns the new function.
|
---|
858 | */
|
---|
859 | function overArg(func, transform) {
|
---|
860 | return function(arg) {
|
---|
861 | return func(transform(arg));
|
---|
862 | };
|
---|
863 | }
|
---|
864 |
|
---|
865 | /* Built-in method references for those with the same name as other `lodash` methods. */
|
---|
866 | var nativeKeys = overArg(Object.keys, Object);
|
---|
867 |
|
---|
868 | /** Used for built-in method references. */
|
---|
869 | var objectProto$4 = Object.prototype;
|
---|
870 |
|
---|
871 | /** Used to check objects for own properties. */
|
---|
872 | var hasOwnProperty$3 = objectProto$4.hasOwnProperty;
|
---|
873 |
|
---|
874 | /**
|
---|
875 | * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
|
---|
876 | *
|
---|
877 | * @private
|
---|
878 | * @param {Object} object The object to query.
|
---|
879 | * @returns {Array} Returns the array of property names.
|
---|
880 | */
|
---|
881 | function baseKeys(object) {
|
---|
882 | if (!isPrototype(object)) {
|
---|
883 | return nativeKeys(object);
|
---|
884 | }
|
---|
885 | var result = [];
|
---|
886 | for (var key in Object(object)) {
|
---|
887 | if (hasOwnProperty$3.call(object, key) && key != 'constructor') {
|
---|
888 | result.push(key);
|
---|
889 | }
|
---|
890 | }
|
---|
891 | return result;
|
---|
892 | }
|
---|
893 |
|
---|
894 | /**
|
---|
895 | * Creates an array of the own enumerable property names of `object`.
|
---|
896 | *
|
---|
897 | * **Note:** Non-object values are coerced to objects. See the
|
---|
898 | * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
|
---|
899 | * for more details.
|
---|
900 | *
|
---|
901 | * @static
|
---|
902 | * @since 0.1.0
|
---|
903 | * @memberOf _
|
---|
904 | * @category Object
|
---|
905 | * @param {Object} object The object to query.
|
---|
906 | * @returns {Array} Returns the array of property names.
|
---|
907 | * @example
|
---|
908 | *
|
---|
909 | * function Foo() {
|
---|
910 | * this.a = 1;
|
---|
911 | * this.b = 2;
|
---|
912 | * }
|
---|
913 | *
|
---|
914 | * Foo.prototype.c = 3;
|
---|
915 | *
|
---|
916 | * _.keys(new Foo);
|
---|
917 | * // => ['a', 'b'] (iteration order is not guaranteed)
|
---|
918 | *
|
---|
919 | * _.keys('hi');
|
---|
920 | * // => ['0', '1']
|
---|
921 | */
|
---|
922 | function keys(object) {
|
---|
923 | return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
|
---|
924 | }
|
---|
925 |
|
---|
926 | function createArrayIterator(coll) {
|
---|
927 | var i = -1;
|
---|
928 | var len = coll.length;
|
---|
929 | return function next() {
|
---|
930 | return ++i < len ? {value: coll[i], key: i} : null;
|
---|
931 | }
|
---|
932 | }
|
---|
933 |
|
---|
934 | function createES2015Iterator(iterator) {
|
---|
935 | var i = -1;
|
---|
936 | return function next() {
|
---|
937 | var item = iterator.next();
|
---|
938 | if (item.done)
|
---|
939 | return null;
|
---|
940 | i++;
|
---|
941 | return {value: item.value, key: i};
|
---|
942 | }
|
---|
943 | }
|
---|
944 |
|
---|
945 | function createObjectIterator(obj) {
|
---|
946 | var okeys = keys(obj);
|
---|
947 | var i = -1;
|
---|
948 | var len = okeys.length;
|
---|
949 | return function next() {
|
---|
950 | var key = okeys[++i];
|
---|
951 | return i < len ? {value: obj[key], key: key} : null;
|
---|
952 | };
|
---|
953 | }
|
---|
954 |
|
---|
955 | function iterator(coll) {
|
---|
956 | if (isArrayLike(coll)) {
|
---|
957 | return createArrayIterator(coll);
|
---|
958 | }
|
---|
959 |
|
---|
960 | var iterator = getIterator(coll);
|
---|
961 | return iterator ? createES2015Iterator(iterator) : createObjectIterator(coll);
|
---|
962 | }
|
---|
963 |
|
---|
964 | function onlyOnce(fn) {
|
---|
965 | return function() {
|
---|
966 | if (fn === null) throw new Error("Callback was already called.");
|
---|
967 | var callFn = fn;
|
---|
968 | fn = null;
|
---|
969 | callFn.apply(this, arguments);
|
---|
970 | };
|
---|
971 | }
|
---|
972 |
|
---|
973 | function _eachOfLimit(limit) {
|
---|
974 | return function (obj, iteratee, callback) {
|
---|
975 | callback = once(callback || noop);
|
---|
976 | if (limit <= 0 || !obj) {
|
---|
977 | return callback(null);
|
---|
978 | }
|
---|
979 | var nextElem = iterator(obj);
|
---|
980 | var done = false;
|
---|
981 | var running = 0;
|
---|
982 | var looping = false;
|
---|
983 |
|
---|
984 | function iterateeCallback(err, value) {
|
---|
985 | running -= 1;
|
---|
986 | if (err) {
|
---|
987 | done = true;
|
---|
988 | callback(err);
|
---|
989 | }
|
---|
990 | else if (value === breakLoop || (done && running <= 0)) {
|
---|
991 | done = true;
|
---|
992 | return callback(null);
|
---|
993 | }
|
---|
994 | else if (!looping) {
|
---|
995 | replenish();
|
---|
996 | }
|
---|
997 | }
|
---|
998 |
|
---|
999 | function replenish () {
|
---|
1000 | looping = true;
|
---|
1001 | while (running < limit && !done) {
|
---|
1002 | var elem = nextElem();
|
---|
1003 | if (elem === null) {
|
---|
1004 | done = true;
|
---|
1005 | if (running <= 0) {
|
---|
1006 | callback(null);
|
---|
1007 | }
|
---|
1008 | return;
|
---|
1009 | }
|
---|
1010 | running += 1;
|
---|
1011 | iteratee(elem.value, elem.key, onlyOnce(iterateeCallback));
|
---|
1012 | }
|
---|
1013 | looping = false;
|
---|
1014 | }
|
---|
1015 |
|
---|
1016 | replenish();
|
---|
1017 | };
|
---|
1018 | }
|
---|
1019 |
|
---|
1020 | /**
|
---|
1021 | * The same as [`eachOf`]{@link module:Collections.eachOf} but runs a maximum of `limit` async operations at a
|
---|
1022 | * time.
|
---|
1023 | *
|
---|
1024 | * @name eachOfLimit
|
---|
1025 | * @static
|
---|
1026 | * @memberOf module:Collections
|
---|
1027 | * @method
|
---|
1028 | * @see [async.eachOf]{@link module:Collections.eachOf}
|
---|
1029 | * @alias forEachOfLimit
|
---|
1030 | * @category Collection
|
---|
1031 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
1032 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
1033 | * @param {AsyncFunction} iteratee - An async function to apply to each
|
---|
1034 | * item in `coll`. The `key` is the item's key, or index in the case of an
|
---|
1035 | * array.
|
---|
1036 | * Invoked with (item, key, callback).
|
---|
1037 | * @param {Function} [callback] - A callback which is called when all
|
---|
1038 | * `iteratee` functions have finished, or an error occurs. Invoked with (err).
|
---|
1039 | */
|
---|
1040 | function eachOfLimit(coll, limit, iteratee, callback) {
|
---|
1041 | _eachOfLimit(limit)(coll, wrapAsync(iteratee), callback);
|
---|
1042 | }
|
---|
1043 |
|
---|
1044 | function doLimit(fn, limit) {
|
---|
1045 | return function (iterable, iteratee, callback) {
|
---|
1046 | return fn(iterable, limit, iteratee, callback);
|
---|
1047 | };
|
---|
1048 | }
|
---|
1049 |
|
---|
1050 | // eachOf implementation optimized for array-likes
|
---|
1051 | function eachOfArrayLike(coll, iteratee, callback) {
|
---|
1052 | callback = once(callback || noop);
|
---|
1053 | var index = 0,
|
---|
1054 | completed = 0,
|
---|
1055 | length = coll.length;
|
---|
1056 | if (length === 0) {
|
---|
1057 | callback(null);
|
---|
1058 | }
|
---|
1059 |
|
---|
1060 | function iteratorCallback(err, value) {
|
---|
1061 | if (err) {
|
---|
1062 | callback(err);
|
---|
1063 | } else if ((++completed === length) || value === breakLoop) {
|
---|
1064 | callback(null);
|
---|
1065 | }
|
---|
1066 | }
|
---|
1067 |
|
---|
1068 | for (; index < length; index++) {
|
---|
1069 | iteratee(coll[index], index, onlyOnce(iteratorCallback));
|
---|
1070 | }
|
---|
1071 | }
|
---|
1072 |
|
---|
1073 | // a generic version of eachOf which can handle array, object, and iterator cases.
|
---|
1074 | var eachOfGeneric = doLimit(eachOfLimit, Infinity);
|
---|
1075 |
|
---|
1076 | /**
|
---|
1077 | * Like [`each`]{@link module:Collections.each}, except that it passes the key (or index) as the second argument
|
---|
1078 | * to the iteratee.
|
---|
1079 | *
|
---|
1080 | * @name eachOf
|
---|
1081 | * @static
|
---|
1082 | * @memberOf module:Collections
|
---|
1083 | * @method
|
---|
1084 | * @alias forEachOf
|
---|
1085 | * @category Collection
|
---|
1086 | * @see [async.each]{@link module:Collections.each}
|
---|
1087 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
1088 | * @param {AsyncFunction} iteratee - A function to apply to each
|
---|
1089 | * item in `coll`.
|
---|
1090 | * The `key` is the item's key, or index in the case of an array.
|
---|
1091 | * Invoked with (item, key, callback).
|
---|
1092 | * @param {Function} [callback] - A callback which is called when all
|
---|
1093 | * `iteratee` functions have finished, or an error occurs. Invoked with (err).
|
---|
1094 | * @example
|
---|
1095 | *
|
---|
1096 | * var obj = {dev: "/dev.json", test: "/test.json", prod: "/prod.json"};
|
---|
1097 | * var configs = {};
|
---|
1098 | *
|
---|
1099 | * async.forEachOf(obj, function (value, key, callback) {
|
---|
1100 | * fs.readFile(__dirname + value, "utf8", function (err, data) {
|
---|
1101 | * if (err) return callback(err);
|
---|
1102 | * try {
|
---|
1103 | * configs[key] = JSON.parse(data);
|
---|
1104 | * } catch (e) {
|
---|
1105 | * return callback(e);
|
---|
1106 | * }
|
---|
1107 | * callback();
|
---|
1108 | * });
|
---|
1109 | * }, function (err) {
|
---|
1110 | * if (err) console.error(err.message);
|
---|
1111 | * // configs is now a map of JSON data
|
---|
1112 | * doSomethingWith(configs);
|
---|
1113 | * });
|
---|
1114 | */
|
---|
1115 | var eachOf = function(coll, iteratee, callback) {
|
---|
1116 | var eachOfImplementation = isArrayLike(coll) ? eachOfArrayLike : eachOfGeneric;
|
---|
1117 | eachOfImplementation(coll, wrapAsync(iteratee), callback);
|
---|
1118 | };
|
---|
1119 |
|
---|
1120 | function doParallel(fn) {
|
---|
1121 | return function (obj, iteratee, callback) {
|
---|
1122 | return fn(eachOf, obj, wrapAsync(iteratee), callback);
|
---|
1123 | };
|
---|
1124 | }
|
---|
1125 |
|
---|
1126 | function _asyncMap(eachfn, arr, iteratee, callback) {
|
---|
1127 | callback = callback || noop;
|
---|
1128 | arr = arr || [];
|
---|
1129 | var results = [];
|
---|
1130 | var counter = 0;
|
---|
1131 | var _iteratee = wrapAsync(iteratee);
|
---|
1132 |
|
---|
1133 | eachfn(arr, function (value, _, callback) {
|
---|
1134 | var index = counter++;
|
---|
1135 | _iteratee(value, function (err, v) {
|
---|
1136 | results[index] = v;
|
---|
1137 | callback(err);
|
---|
1138 | });
|
---|
1139 | }, function (err) {
|
---|
1140 | callback(err, results);
|
---|
1141 | });
|
---|
1142 | }
|
---|
1143 |
|
---|
1144 | /**
|
---|
1145 | * Produces a new collection of values by mapping each value in `coll` through
|
---|
1146 | * the `iteratee` function. The `iteratee` is called with an item from `coll`
|
---|
1147 | * and a callback for when it has finished processing. Each of these callback
|
---|
1148 | * takes 2 arguments: an `error`, and the transformed item from `coll`. If
|
---|
1149 | * `iteratee` passes an error to its callback, the main `callback` (for the
|
---|
1150 | * `map` function) is immediately called with the error.
|
---|
1151 | *
|
---|
1152 | * Note, that since this function applies the `iteratee` to each item in
|
---|
1153 | * parallel, there is no guarantee that the `iteratee` functions will complete
|
---|
1154 | * in order. However, the results array will be in the same order as the
|
---|
1155 | * original `coll`.
|
---|
1156 | *
|
---|
1157 | * If `map` is passed an Object, the results will be an Array. The results
|
---|
1158 | * will roughly be in the order of the original Objects' keys (but this can
|
---|
1159 | * vary across JavaScript engines).
|
---|
1160 | *
|
---|
1161 | * @name map
|
---|
1162 | * @static
|
---|
1163 | * @memberOf module:Collections
|
---|
1164 | * @method
|
---|
1165 | * @category Collection
|
---|
1166 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
1167 | * @param {AsyncFunction} iteratee - An async function to apply to each item in
|
---|
1168 | * `coll`.
|
---|
1169 | * The iteratee should complete with the transformed item.
|
---|
1170 | * Invoked with (item, callback).
|
---|
1171 | * @param {Function} [callback] - A callback which is called when all `iteratee`
|
---|
1172 | * functions have finished, or an error occurs. Results is an Array of the
|
---|
1173 | * transformed items from the `coll`. Invoked with (err, results).
|
---|
1174 | * @example
|
---|
1175 | *
|
---|
1176 | * async.map(['file1','file2','file3'], fs.stat, function(err, results) {
|
---|
1177 | * // results is now an array of stats for each file
|
---|
1178 | * });
|
---|
1179 | */
|
---|
1180 | var map = doParallel(_asyncMap);
|
---|
1181 |
|
---|
1182 | /**
|
---|
1183 | * Applies the provided arguments to each function in the array, calling
|
---|
1184 | * `callback` after all functions have completed. If you only provide the first
|
---|
1185 | * argument, `fns`, then it will return a function which lets you pass in the
|
---|
1186 | * arguments as if it were a single function call. If more arguments are
|
---|
1187 | * provided, `callback` is required while `args` is still optional.
|
---|
1188 | *
|
---|
1189 | * @name applyEach
|
---|
1190 | * @static
|
---|
1191 | * @memberOf module:ControlFlow
|
---|
1192 | * @method
|
---|
1193 | * @category Control Flow
|
---|
1194 | * @param {Array|Iterable|Object} fns - A collection of {@link AsyncFunction}s
|
---|
1195 | * to all call with the same arguments
|
---|
1196 | * @param {...*} [args] - any number of separate arguments to pass to the
|
---|
1197 | * function.
|
---|
1198 | * @param {Function} [callback] - the final argument should be the callback,
|
---|
1199 | * called when all functions have completed processing.
|
---|
1200 | * @returns {Function} - If only the first argument, `fns`, is provided, it will
|
---|
1201 | * return a function which lets you pass in the arguments as if it were a single
|
---|
1202 | * function call. The signature is `(..args, callback)`. If invoked with any
|
---|
1203 | * arguments, `callback` is required.
|
---|
1204 | * @example
|
---|
1205 | *
|
---|
1206 | * async.applyEach([enableSearch, updateSchema], 'bucket', callback);
|
---|
1207 | *
|
---|
1208 | * // partial application example:
|
---|
1209 | * async.each(
|
---|
1210 | * buckets,
|
---|
1211 | * async.applyEach([enableSearch, updateSchema]),
|
---|
1212 | * callback
|
---|
1213 | * );
|
---|
1214 | */
|
---|
1215 | var applyEach = applyEach$1(map);
|
---|
1216 |
|
---|
1217 | function doParallelLimit(fn) {
|
---|
1218 | return function (obj, limit, iteratee, callback) {
|
---|
1219 | return fn(_eachOfLimit(limit), obj, wrapAsync(iteratee), callback);
|
---|
1220 | };
|
---|
1221 | }
|
---|
1222 |
|
---|
1223 | /**
|
---|
1224 | * The same as [`map`]{@link module:Collections.map} but runs a maximum of `limit` async operations at a time.
|
---|
1225 | *
|
---|
1226 | * @name mapLimit
|
---|
1227 | * @static
|
---|
1228 | * @memberOf module:Collections
|
---|
1229 | * @method
|
---|
1230 | * @see [async.map]{@link module:Collections.map}
|
---|
1231 | * @category Collection
|
---|
1232 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
1233 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
1234 | * @param {AsyncFunction} iteratee - An async function to apply to each item in
|
---|
1235 | * `coll`.
|
---|
1236 | * The iteratee should complete with the transformed item.
|
---|
1237 | * Invoked with (item, callback).
|
---|
1238 | * @param {Function} [callback] - A callback which is called when all `iteratee`
|
---|
1239 | * functions have finished, or an error occurs. Results is an array of the
|
---|
1240 | * transformed items from the `coll`. Invoked with (err, results).
|
---|
1241 | */
|
---|
1242 | var mapLimit = doParallelLimit(_asyncMap);
|
---|
1243 |
|
---|
1244 | /**
|
---|
1245 | * The same as [`map`]{@link module:Collections.map} but runs only a single async operation at a time.
|
---|
1246 | *
|
---|
1247 | * @name mapSeries
|
---|
1248 | * @static
|
---|
1249 | * @memberOf module:Collections
|
---|
1250 | * @method
|
---|
1251 | * @see [async.map]{@link module:Collections.map}
|
---|
1252 | * @category Collection
|
---|
1253 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
1254 | * @param {AsyncFunction} iteratee - An async function to apply to each item in
|
---|
1255 | * `coll`.
|
---|
1256 | * The iteratee should complete with the transformed item.
|
---|
1257 | * Invoked with (item, callback).
|
---|
1258 | * @param {Function} [callback] - A callback which is called when all `iteratee`
|
---|
1259 | * functions have finished, or an error occurs. Results is an array of the
|
---|
1260 | * transformed items from the `coll`. Invoked with (err, results).
|
---|
1261 | */
|
---|
1262 | var mapSeries = doLimit(mapLimit, 1);
|
---|
1263 |
|
---|
1264 | /**
|
---|
1265 | * The same as [`applyEach`]{@link module:ControlFlow.applyEach} but runs only a single async operation at a time.
|
---|
1266 | *
|
---|
1267 | * @name applyEachSeries
|
---|
1268 | * @static
|
---|
1269 | * @memberOf module:ControlFlow
|
---|
1270 | * @method
|
---|
1271 | * @see [async.applyEach]{@link module:ControlFlow.applyEach}
|
---|
1272 | * @category Control Flow
|
---|
1273 | * @param {Array|Iterable|Object} fns - A collection of {@link AsyncFunction}s to all
|
---|
1274 | * call with the same arguments
|
---|
1275 | * @param {...*} [args] - any number of separate arguments to pass to the
|
---|
1276 | * function.
|
---|
1277 | * @param {Function} [callback] - the final argument should be the callback,
|
---|
1278 | * called when all functions have completed processing.
|
---|
1279 | * @returns {Function} - If only the first argument is provided, it will return
|
---|
1280 | * a function which lets you pass in the arguments as if it were a single
|
---|
1281 | * function call.
|
---|
1282 | */
|
---|
1283 | var applyEachSeries = applyEach$1(mapSeries);
|
---|
1284 |
|
---|
1285 | /**
|
---|
1286 | * A specialized version of `_.forEach` for arrays without support for
|
---|
1287 | * iteratee shorthands.
|
---|
1288 | *
|
---|
1289 | * @private
|
---|
1290 | * @param {Array} [array] The array to iterate over.
|
---|
1291 | * @param {Function} iteratee The function invoked per iteration.
|
---|
1292 | * @returns {Array} Returns `array`.
|
---|
1293 | */
|
---|
1294 | function arrayEach(array, iteratee) {
|
---|
1295 | var index = -1,
|
---|
1296 | length = array == null ? 0 : array.length;
|
---|
1297 |
|
---|
1298 | while (++index < length) {
|
---|
1299 | if (iteratee(array[index], index, array) === false) {
|
---|
1300 | break;
|
---|
1301 | }
|
---|
1302 | }
|
---|
1303 | return array;
|
---|
1304 | }
|
---|
1305 |
|
---|
1306 | /**
|
---|
1307 | * Creates a base function for methods like `_.forIn` and `_.forOwn`.
|
---|
1308 | *
|
---|
1309 | * @private
|
---|
1310 | * @param {boolean} [fromRight] Specify iterating from right to left.
|
---|
1311 | * @returns {Function} Returns the new base function.
|
---|
1312 | */
|
---|
1313 | function createBaseFor(fromRight) {
|
---|
1314 | return function(object, iteratee, keysFunc) {
|
---|
1315 | var index = -1,
|
---|
1316 | iterable = Object(object),
|
---|
1317 | props = keysFunc(object),
|
---|
1318 | length = props.length;
|
---|
1319 |
|
---|
1320 | while (length--) {
|
---|
1321 | var key = props[fromRight ? length : ++index];
|
---|
1322 | if (iteratee(iterable[key], key, iterable) === false) {
|
---|
1323 | break;
|
---|
1324 | }
|
---|
1325 | }
|
---|
1326 | return object;
|
---|
1327 | };
|
---|
1328 | }
|
---|
1329 |
|
---|
1330 | /**
|
---|
1331 | * The base implementation of `baseForOwn` which iterates over `object`
|
---|
1332 | * properties returned by `keysFunc` and invokes `iteratee` for each property.
|
---|
1333 | * Iteratee functions may exit iteration early by explicitly returning `false`.
|
---|
1334 | *
|
---|
1335 | * @private
|
---|
1336 | * @param {Object} object The object to iterate over.
|
---|
1337 | * @param {Function} iteratee The function invoked per iteration.
|
---|
1338 | * @param {Function} keysFunc The function to get the keys of `object`.
|
---|
1339 | * @returns {Object} Returns `object`.
|
---|
1340 | */
|
---|
1341 | var baseFor = createBaseFor();
|
---|
1342 |
|
---|
1343 | /**
|
---|
1344 | * The base implementation of `_.forOwn` without support for iteratee shorthands.
|
---|
1345 | *
|
---|
1346 | * @private
|
---|
1347 | * @param {Object} object The object to iterate over.
|
---|
1348 | * @param {Function} iteratee The function invoked per iteration.
|
---|
1349 | * @returns {Object} Returns `object`.
|
---|
1350 | */
|
---|
1351 | function baseForOwn(object, iteratee) {
|
---|
1352 | return object && baseFor(object, iteratee, keys);
|
---|
1353 | }
|
---|
1354 |
|
---|
1355 | /**
|
---|
1356 | * The base implementation of `_.findIndex` and `_.findLastIndex` without
|
---|
1357 | * support for iteratee shorthands.
|
---|
1358 | *
|
---|
1359 | * @private
|
---|
1360 | * @param {Array} array The array to inspect.
|
---|
1361 | * @param {Function} predicate The function invoked per iteration.
|
---|
1362 | * @param {number} fromIndex The index to search from.
|
---|
1363 | * @param {boolean} [fromRight] Specify iterating from right to left.
|
---|
1364 | * @returns {number} Returns the index of the matched value, else `-1`.
|
---|
1365 | */
|
---|
1366 | function baseFindIndex(array, predicate, fromIndex, fromRight) {
|
---|
1367 | var length = array.length,
|
---|
1368 | index = fromIndex + (fromRight ? 1 : -1);
|
---|
1369 |
|
---|
1370 | while ((fromRight ? index-- : ++index < length)) {
|
---|
1371 | if (predicate(array[index], index, array)) {
|
---|
1372 | return index;
|
---|
1373 | }
|
---|
1374 | }
|
---|
1375 | return -1;
|
---|
1376 | }
|
---|
1377 |
|
---|
1378 | /**
|
---|
1379 | * The base implementation of `_.isNaN` without support for number objects.
|
---|
1380 | *
|
---|
1381 | * @private
|
---|
1382 | * @param {*} value The value to check.
|
---|
1383 | * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
|
---|
1384 | */
|
---|
1385 | function baseIsNaN(value) {
|
---|
1386 | return value !== value;
|
---|
1387 | }
|
---|
1388 |
|
---|
1389 | /**
|
---|
1390 | * A specialized version of `_.indexOf` which performs strict equality
|
---|
1391 | * comparisons of values, i.e. `===`.
|
---|
1392 | *
|
---|
1393 | * @private
|
---|
1394 | * @param {Array} array The array to inspect.
|
---|
1395 | * @param {*} value The value to search for.
|
---|
1396 | * @param {number} fromIndex The index to search from.
|
---|
1397 | * @returns {number} Returns the index of the matched value, else `-1`.
|
---|
1398 | */
|
---|
1399 | function strictIndexOf(array, value, fromIndex) {
|
---|
1400 | var index = fromIndex - 1,
|
---|
1401 | length = array.length;
|
---|
1402 |
|
---|
1403 | while (++index < length) {
|
---|
1404 | if (array[index] === value) {
|
---|
1405 | return index;
|
---|
1406 | }
|
---|
1407 | }
|
---|
1408 | return -1;
|
---|
1409 | }
|
---|
1410 |
|
---|
1411 | /**
|
---|
1412 | * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
|
---|
1413 | *
|
---|
1414 | * @private
|
---|
1415 | * @param {Array} array The array to inspect.
|
---|
1416 | * @param {*} value The value to search for.
|
---|
1417 | * @param {number} fromIndex The index to search from.
|
---|
1418 | * @returns {number} Returns the index of the matched value, else `-1`.
|
---|
1419 | */
|
---|
1420 | function baseIndexOf(array, value, fromIndex) {
|
---|
1421 | return value === value
|
---|
1422 | ? strictIndexOf(array, value, fromIndex)
|
---|
1423 | : baseFindIndex(array, baseIsNaN, fromIndex);
|
---|
1424 | }
|
---|
1425 |
|
---|
1426 | /**
|
---|
1427 | * Determines the best order for running the {@link AsyncFunction}s in `tasks`, based on
|
---|
1428 | * their requirements. Each function can optionally depend on other functions
|
---|
1429 | * being completed first, and each function is run as soon as its requirements
|
---|
1430 | * are satisfied.
|
---|
1431 | *
|
---|
1432 | * If any of the {@link AsyncFunction}s pass an error to their callback, the `auto` sequence
|
---|
1433 | * will stop. Further tasks will not execute (so any other functions depending
|
---|
1434 | * on it will not run), and the main `callback` is immediately called with the
|
---|
1435 | * error.
|
---|
1436 | *
|
---|
1437 | * {@link AsyncFunction}s also receive an object containing the results of functions which
|
---|
1438 | * have completed so far as the first argument, if they have dependencies. If a
|
---|
1439 | * task function has no dependencies, it will only be passed a callback.
|
---|
1440 | *
|
---|
1441 | * @name auto
|
---|
1442 | * @static
|
---|
1443 | * @memberOf module:ControlFlow
|
---|
1444 | * @method
|
---|
1445 | * @category Control Flow
|
---|
1446 | * @param {Object} tasks - An object. Each of its properties is either a
|
---|
1447 | * function or an array of requirements, with the {@link AsyncFunction} itself the last item
|
---|
1448 | * in the array. The object's key of a property serves as the name of the task
|
---|
1449 | * defined by that property, i.e. can be used when specifying requirements for
|
---|
1450 | * other tasks. The function receives one or two arguments:
|
---|
1451 | * * a `results` object, containing the results of the previously executed
|
---|
1452 | * functions, only passed if the task has any dependencies,
|
---|
1453 | * * a `callback(err, result)` function, which must be called when finished,
|
---|
1454 | * passing an `error` (which can be `null`) and the result of the function's
|
---|
1455 | * execution.
|
---|
1456 | * @param {number} [concurrency=Infinity] - An optional `integer` for
|
---|
1457 | * determining the maximum number of tasks that can be run in parallel. By
|
---|
1458 | * default, as many as possible.
|
---|
1459 | * @param {Function} [callback] - An optional callback which is called when all
|
---|
1460 | * the tasks have been completed. It receives the `err` argument if any `tasks`
|
---|
1461 | * pass an error to their callback. Results are always returned; however, if an
|
---|
1462 | * error occurs, no further `tasks` will be performed, and the results object
|
---|
1463 | * will only contain partial results. Invoked with (err, results).
|
---|
1464 | * @returns undefined
|
---|
1465 | * @example
|
---|
1466 | *
|
---|
1467 | * async.auto({
|
---|
1468 | * // this function will just be passed a callback
|
---|
1469 | * readData: async.apply(fs.readFile, 'data.txt', 'utf-8'),
|
---|
1470 | * showData: ['readData', function(results, cb) {
|
---|
1471 | * // results.readData is the file's contents
|
---|
1472 | * // ...
|
---|
1473 | * }]
|
---|
1474 | * }, callback);
|
---|
1475 | *
|
---|
1476 | * async.auto({
|
---|
1477 | * get_data: function(callback) {
|
---|
1478 | * console.log('in get_data');
|
---|
1479 | * // async code to get some data
|
---|
1480 | * callback(null, 'data', 'converted to array');
|
---|
1481 | * },
|
---|
1482 | * make_folder: function(callback) {
|
---|
1483 | * console.log('in make_folder');
|
---|
1484 | * // async code to create a directory to store a file in
|
---|
1485 | * // this is run at the same time as getting the data
|
---|
1486 | * callback(null, 'folder');
|
---|
1487 | * },
|
---|
1488 | * write_file: ['get_data', 'make_folder', function(results, callback) {
|
---|
1489 | * console.log('in write_file', JSON.stringify(results));
|
---|
1490 | * // once there is some data and the directory exists,
|
---|
1491 | * // write the data to a file in the directory
|
---|
1492 | * callback(null, 'filename');
|
---|
1493 | * }],
|
---|
1494 | * email_link: ['write_file', function(results, callback) {
|
---|
1495 | * console.log('in email_link', JSON.stringify(results));
|
---|
1496 | * // once the file is written let's email a link to it...
|
---|
1497 | * // results.write_file contains the filename returned by write_file.
|
---|
1498 | * callback(null, {'file':results.write_file, 'email':'user@example.com'});
|
---|
1499 | * }]
|
---|
1500 | * }, function(err, results) {
|
---|
1501 | * console.log('err = ', err);
|
---|
1502 | * console.log('results = ', results);
|
---|
1503 | * });
|
---|
1504 | */
|
---|
1505 | var auto = function (tasks, concurrency, callback) {
|
---|
1506 | if (typeof concurrency === 'function') {
|
---|
1507 | // concurrency is optional, shift the args.
|
---|
1508 | callback = concurrency;
|
---|
1509 | concurrency = null;
|
---|
1510 | }
|
---|
1511 | callback = once(callback || noop);
|
---|
1512 | var keys$$1 = keys(tasks);
|
---|
1513 | var numTasks = keys$$1.length;
|
---|
1514 | if (!numTasks) {
|
---|
1515 | return callback(null);
|
---|
1516 | }
|
---|
1517 | if (!concurrency) {
|
---|
1518 | concurrency = numTasks;
|
---|
1519 | }
|
---|
1520 |
|
---|
1521 | var results = {};
|
---|
1522 | var runningTasks = 0;
|
---|
1523 | var hasError = false;
|
---|
1524 |
|
---|
1525 | var listeners = Object.create(null);
|
---|
1526 |
|
---|
1527 | var readyTasks = [];
|
---|
1528 |
|
---|
1529 | // for cycle detection:
|
---|
1530 | var readyToCheck = []; // tasks that have been identified as reachable
|
---|
1531 | // without the possibility of returning to an ancestor task
|
---|
1532 | var uncheckedDependencies = {};
|
---|
1533 |
|
---|
1534 | baseForOwn(tasks, function (task, key) {
|
---|
1535 | if (!isArray(task)) {
|
---|
1536 | // no dependencies
|
---|
1537 | enqueueTask(key, [task]);
|
---|
1538 | readyToCheck.push(key);
|
---|
1539 | return;
|
---|
1540 | }
|
---|
1541 |
|
---|
1542 | var dependencies = task.slice(0, task.length - 1);
|
---|
1543 | var remainingDependencies = dependencies.length;
|
---|
1544 | if (remainingDependencies === 0) {
|
---|
1545 | enqueueTask(key, task);
|
---|
1546 | readyToCheck.push(key);
|
---|
1547 | return;
|
---|
1548 | }
|
---|
1549 | uncheckedDependencies[key] = remainingDependencies;
|
---|
1550 |
|
---|
1551 | arrayEach(dependencies, function (dependencyName) {
|
---|
1552 | if (!tasks[dependencyName]) {
|
---|
1553 | throw new Error('async.auto task `' + key +
|
---|
1554 | '` has a non-existent dependency `' +
|
---|
1555 | dependencyName + '` in ' +
|
---|
1556 | dependencies.join(', '));
|
---|
1557 | }
|
---|
1558 | addListener(dependencyName, function () {
|
---|
1559 | remainingDependencies--;
|
---|
1560 | if (remainingDependencies === 0) {
|
---|
1561 | enqueueTask(key, task);
|
---|
1562 | }
|
---|
1563 | });
|
---|
1564 | });
|
---|
1565 | });
|
---|
1566 |
|
---|
1567 | checkForDeadlocks();
|
---|
1568 | processQueue();
|
---|
1569 |
|
---|
1570 | function enqueueTask(key, task) {
|
---|
1571 | readyTasks.push(function () {
|
---|
1572 | runTask(key, task);
|
---|
1573 | });
|
---|
1574 | }
|
---|
1575 |
|
---|
1576 | function processQueue() {
|
---|
1577 | if (readyTasks.length === 0 && runningTasks === 0) {
|
---|
1578 | return callback(null, results);
|
---|
1579 | }
|
---|
1580 | while(readyTasks.length && runningTasks < concurrency) {
|
---|
1581 | var run = readyTasks.shift();
|
---|
1582 | run();
|
---|
1583 | }
|
---|
1584 |
|
---|
1585 | }
|
---|
1586 |
|
---|
1587 | function addListener(taskName, fn) {
|
---|
1588 | var taskListeners = listeners[taskName];
|
---|
1589 | if (!taskListeners) {
|
---|
1590 | taskListeners = listeners[taskName] = [];
|
---|
1591 | }
|
---|
1592 |
|
---|
1593 | taskListeners.push(fn);
|
---|
1594 | }
|
---|
1595 |
|
---|
1596 | function taskComplete(taskName) {
|
---|
1597 | var taskListeners = listeners[taskName] || [];
|
---|
1598 | arrayEach(taskListeners, function (fn) {
|
---|
1599 | fn();
|
---|
1600 | });
|
---|
1601 | processQueue();
|
---|
1602 | }
|
---|
1603 |
|
---|
1604 |
|
---|
1605 | function runTask(key, task) {
|
---|
1606 | if (hasError) return;
|
---|
1607 |
|
---|
1608 | var taskCallback = onlyOnce(function(err, result) {
|
---|
1609 | runningTasks--;
|
---|
1610 | if (arguments.length > 2) {
|
---|
1611 | result = slice(arguments, 1);
|
---|
1612 | }
|
---|
1613 | if (err) {
|
---|
1614 | var safeResults = {};
|
---|
1615 | baseForOwn(results, function(val, rkey) {
|
---|
1616 | safeResults[rkey] = val;
|
---|
1617 | });
|
---|
1618 | safeResults[key] = result;
|
---|
1619 | hasError = true;
|
---|
1620 | listeners = Object.create(null);
|
---|
1621 |
|
---|
1622 | callback(err, safeResults);
|
---|
1623 | } else {
|
---|
1624 | results[key] = result;
|
---|
1625 | taskComplete(key);
|
---|
1626 | }
|
---|
1627 | });
|
---|
1628 |
|
---|
1629 | runningTasks++;
|
---|
1630 | var taskFn = wrapAsync(task[task.length - 1]);
|
---|
1631 | if (task.length > 1) {
|
---|
1632 | taskFn(results, taskCallback);
|
---|
1633 | } else {
|
---|
1634 | taskFn(taskCallback);
|
---|
1635 | }
|
---|
1636 | }
|
---|
1637 |
|
---|
1638 | function checkForDeadlocks() {
|
---|
1639 | // Kahn's algorithm
|
---|
1640 | // https://en.wikipedia.org/wiki/Topological_sorting#Kahn.27s_algorithm
|
---|
1641 | // http://connalle.blogspot.com/2013/10/topological-sortingkahn-algorithm.html
|
---|
1642 | var currentTask;
|
---|
1643 | var counter = 0;
|
---|
1644 | while (readyToCheck.length) {
|
---|
1645 | currentTask = readyToCheck.pop();
|
---|
1646 | counter++;
|
---|
1647 | arrayEach(getDependents(currentTask), function (dependent) {
|
---|
1648 | if (--uncheckedDependencies[dependent] === 0) {
|
---|
1649 | readyToCheck.push(dependent);
|
---|
1650 | }
|
---|
1651 | });
|
---|
1652 | }
|
---|
1653 |
|
---|
1654 | if (counter !== numTasks) {
|
---|
1655 | throw new Error(
|
---|
1656 | 'async.auto cannot execute tasks due to a recursive dependency'
|
---|
1657 | );
|
---|
1658 | }
|
---|
1659 | }
|
---|
1660 |
|
---|
1661 | function getDependents(taskName) {
|
---|
1662 | var result = [];
|
---|
1663 | baseForOwn(tasks, function (task, key) {
|
---|
1664 | if (isArray(task) && baseIndexOf(task, taskName, 0) >= 0) {
|
---|
1665 | result.push(key);
|
---|
1666 | }
|
---|
1667 | });
|
---|
1668 | return result;
|
---|
1669 | }
|
---|
1670 | };
|
---|
1671 |
|
---|
1672 | /**
|
---|
1673 | * A specialized version of `_.map` for arrays without support for iteratee
|
---|
1674 | * shorthands.
|
---|
1675 | *
|
---|
1676 | * @private
|
---|
1677 | * @param {Array} [array] The array to iterate over.
|
---|
1678 | * @param {Function} iteratee The function invoked per iteration.
|
---|
1679 | * @returns {Array} Returns the new mapped array.
|
---|
1680 | */
|
---|
1681 | function arrayMap(array, iteratee) {
|
---|
1682 | var index = -1,
|
---|
1683 | length = array == null ? 0 : array.length,
|
---|
1684 | result = Array(length);
|
---|
1685 |
|
---|
1686 | while (++index < length) {
|
---|
1687 | result[index] = iteratee(array[index], index, array);
|
---|
1688 | }
|
---|
1689 | return result;
|
---|
1690 | }
|
---|
1691 |
|
---|
1692 | /** `Object#toString` result references. */
|
---|
1693 | var symbolTag = '[object Symbol]';
|
---|
1694 |
|
---|
1695 | /**
|
---|
1696 | * Checks if `value` is classified as a `Symbol` primitive or object.
|
---|
1697 | *
|
---|
1698 | * @static
|
---|
1699 | * @memberOf _
|
---|
1700 | * @since 4.0.0
|
---|
1701 | * @category Lang
|
---|
1702 | * @param {*} value The value to check.
|
---|
1703 | * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
|
---|
1704 | * @example
|
---|
1705 | *
|
---|
1706 | * _.isSymbol(Symbol.iterator);
|
---|
1707 | * // => true
|
---|
1708 | *
|
---|
1709 | * _.isSymbol('abc');
|
---|
1710 | * // => false
|
---|
1711 | */
|
---|
1712 | function isSymbol(value) {
|
---|
1713 | return typeof value == 'symbol' ||
|
---|
1714 | (isObjectLike(value) && baseGetTag(value) == symbolTag);
|
---|
1715 | }
|
---|
1716 |
|
---|
1717 | /** Used as references for various `Number` constants. */
|
---|
1718 | var INFINITY = 1 / 0;
|
---|
1719 |
|
---|
1720 | /** Used to convert symbols to primitives and strings. */
|
---|
1721 | var symbolProto = Symbol$1 ? Symbol$1.prototype : undefined;
|
---|
1722 | var symbolToString = symbolProto ? symbolProto.toString : undefined;
|
---|
1723 |
|
---|
1724 | /**
|
---|
1725 | * The base implementation of `_.toString` which doesn't convert nullish
|
---|
1726 | * values to empty strings.
|
---|
1727 | *
|
---|
1728 | * @private
|
---|
1729 | * @param {*} value The value to process.
|
---|
1730 | * @returns {string} Returns the string.
|
---|
1731 | */
|
---|
1732 | function baseToString(value) {
|
---|
1733 | // Exit early for strings to avoid a performance hit in some environments.
|
---|
1734 | if (typeof value == 'string') {
|
---|
1735 | return value;
|
---|
1736 | }
|
---|
1737 | if (isArray(value)) {
|
---|
1738 | // Recursively convert values (susceptible to call stack limits).
|
---|
1739 | return arrayMap(value, baseToString) + '';
|
---|
1740 | }
|
---|
1741 | if (isSymbol(value)) {
|
---|
1742 | return symbolToString ? symbolToString.call(value) : '';
|
---|
1743 | }
|
---|
1744 | var result = (value + '');
|
---|
1745 | return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
|
---|
1746 | }
|
---|
1747 |
|
---|
1748 | /**
|
---|
1749 | * The base implementation of `_.slice` without an iteratee call guard.
|
---|
1750 | *
|
---|
1751 | * @private
|
---|
1752 | * @param {Array} array The array to slice.
|
---|
1753 | * @param {number} [start=0] The start position.
|
---|
1754 | * @param {number} [end=array.length] The end position.
|
---|
1755 | * @returns {Array} Returns the slice of `array`.
|
---|
1756 | */
|
---|
1757 | function baseSlice(array, start, end) {
|
---|
1758 | var index = -1,
|
---|
1759 | length = array.length;
|
---|
1760 |
|
---|
1761 | if (start < 0) {
|
---|
1762 | start = -start > length ? 0 : (length + start);
|
---|
1763 | }
|
---|
1764 | end = end > length ? length : end;
|
---|
1765 | if (end < 0) {
|
---|
1766 | end += length;
|
---|
1767 | }
|
---|
1768 | length = start > end ? 0 : ((end - start) >>> 0);
|
---|
1769 | start >>>= 0;
|
---|
1770 |
|
---|
1771 | var result = Array(length);
|
---|
1772 | while (++index < length) {
|
---|
1773 | result[index] = array[index + start];
|
---|
1774 | }
|
---|
1775 | return result;
|
---|
1776 | }
|
---|
1777 |
|
---|
1778 | /**
|
---|
1779 | * Casts `array` to a slice if it's needed.
|
---|
1780 | *
|
---|
1781 | * @private
|
---|
1782 | * @param {Array} array The array to inspect.
|
---|
1783 | * @param {number} start The start position.
|
---|
1784 | * @param {number} [end=array.length] The end position.
|
---|
1785 | * @returns {Array} Returns the cast slice.
|
---|
1786 | */
|
---|
1787 | function castSlice(array, start, end) {
|
---|
1788 | var length = array.length;
|
---|
1789 | end = end === undefined ? length : end;
|
---|
1790 | return (!start && end >= length) ? array : baseSlice(array, start, end);
|
---|
1791 | }
|
---|
1792 |
|
---|
1793 | /**
|
---|
1794 | * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
|
---|
1795 | * that is not found in the character symbols.
|
---|
1796 | *
|
---|
1797 | * @private
|
---|
1798 | * @param {Array} strSymbols The string symbols to inspect.
|
---|
1799 | * @param {Array} chrSymbols The character symbols to find.
|
---|
1800 | * @returns {number} Returns the index of the last unmatched string symbol.
|
---|
1801 | */
|
---|
1802 | function charsEndIndex(strSymbols, chrSymbols) {
|
---|
1803 | var index = strSymbols.length;
|
---|
1804 |
|
---|
1805 | while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
|
---|
1806 | return index;
|
---|
1807 | }
|
---|
1808 |
|
---|
1809 | /**
|
---|
1810 | * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
|
---|
1811 | * that is not found in the character symbols.
|
---|
1812 | *
|
---|
1813 | * @private
|
---|
1814 | * @param {Array} strSymbols The string symbols to inspect.
|
---|
1815 | * @param {Array} chrSymbols The character symbols to find.
|
---|
1816 | * @returns {number} Returns the index of the first unmatched string symbol.
|
---|
1817 | */
|
---|
1818 | function charsStartIndex(strSymbols, chrSymbols) {
|
---|
1819 | var index = -1,
|
---|
1820 | length = strSymbols.length;
|
---|
1821 |
|
---|
1822 | while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
|
---|
1823 | return index;
|
---|
1824 | }
|
---|
1825 |
|
---|
1826 | /**
|
---|
1827 | * Converts an ASCII `string` to an array.
|
---|
1828 | *
|
---|
1829 | * @private
|
---|
1830 | * @param {string} string The string to convert.
|
---|
1831 | * @returns {Array} Returns the converted array.
|
---|
1832 | */
|
---|
1833 | function asciiToArray(string) {
|
---|
1834 | return string.split('');
|
---|
1835 | }
|
---|
1836 |
|
---|
1837 | /** Used to compose unicode character classes. */
|
---|
1838 | var rsAstralRange = '\\ud800-\\udfff';
|
---|
1839 | var rsComboMarksRange = '\\u0300-\\u036f';
|
---|
1840 | var reComboHalfMarksRange = '\\ufe20-\\ufe2f';
|
---|
1841 | var rsComboSymbolsRange = '\\u20d0-\\u20ff';
|
---|
1842 | var rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange;
|
---|
1843 | var rsVarRange = '\\ufe0e\\ufe0f';
|
---|
1844 |
|
---|
1845 | /** Used to compose unicode capture groups. */
|
---|
1846 | var rsZWJ = '\\u200d';
|
---|
1847 |
|
---|
1848 | /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
|
---|
1849 | var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');
|
---|
1850 |
|
---|
1851 | /**
|
---|
1852 | * Checks if `string` contains Unicode symbols.
|
---|
1853 | *
|
---|
1854 | * @private
|
---|
1855 | * @param {string} string The string to inspect.
|
---|
1856 | * @returns {boolean} Returns `true` if a symbol is found, else `false`.
|
---|
1857 | */
|
---|
1858 | function hasUnicode(string) {
|
---|
1859 | return reHasUnicode.test(string);
|
---|
1860 | }
|
---|
1861 |
|
---|
1862 | /** Used to compose unicode character classes. */
|
---|
1863 | var rsAstralRange$1 = '\\ud800-\\udfff';
|
---|
1864 | var rsComboMarksRange$1 = '\\u0300-\\u036f';
|
---|
1865 | var reComboHalfMarksRange$1 = '\\ufe20-\\ufe2f';
|
---|
1866 | var rsComboSymbolsRange$1 = '\\u20d0-\\u20ff';
|
---|
1867 | var rsComboRange$1 = rsComboMarksRange$1 + reComboHalfMarksRange$1 + rsComboSymbolsRange$1;
|
---|
1868 | var rsVarRange$1 = '\\ufe0e\\ufe0f';
|
---|
1869 |
|
---|
1870 | /** Used to compose unicode capture groups. */
|
---|
1871 | var rsAstral = '[' + rsAstralRange$1 + ']';
|
---|
1872 | var rsCombo = '[' + rsComboRange$1 + ']';
|
---|
1873 | var rsFitz = '\\ud83c[\\udffb-\\udfff]';
|
---|
1874 | var rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')';
|
---|
1875 | var rsNonAstral = '[^' + rsAstralRange$1 + ']';
|
---|
1876 | var rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}';
|
---|
1877 | var rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]';
|
---|
1878 | var rsZWJ$1 = '\\u200d';
|
---|
1879 |
|
---|
1880 | /** Used to compose unicode regexes. */
|
---|
1881 | var reOptMod = rsModifier + '?';
|
---|
1882 | var rsOptVar = '[' + rsVarRange$1 + ']?';
|
---|
1883 | var rsOptJoin = '(?:' + rsZWJ$1 + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*';
|
---|
1884 | var rsSeq = rsOptVar + reOptMod + rsOptJoin;
|
---|
1885 | var rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
|
---|
1886 |
|
---|
1887 | /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
|
---|
1888 | var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
|
---|
1889 |
|
---|
1890 | /**
|
---|
1891 | * Converts a Unicode `string` to an array.
|
---|
1892 | *
|
---|
1893 | * @private
|
---|
1894 | * @param {string} string The string to convert.
|
---|
1895 | * @returns {Array} Returns the converted array.
|
---|
1896 | */
|
---|
1897 | function unicodeToArray(string) {
|
---|
1898 | return string.match(reUnicode) || [];
|
---|
1899 | }
|
---|
1900 |
|
---|
1901 | /**
|
---|
1902 | * Converts `string` to an array.
|
---|
1903 | *
|
---|
1904 | * @private
|
---|
1905 | * @param {string} string The string to convert.
|
---|
1906 | * @returns {Array} Returns the converted array.
|
---|
1907 | */
|
---|
1908 | function stringToArray(string) {
|
---|
1909 | return hasUnicode(string)
|
---|
1910 | ? unicodeToArray(string)
|
---|
1911 | : asciiToArray(string);
|
---|
1912 | }
|
---|
1913 |
|
---|
1914 | /**
|
---|
1915 | * Converts `value` to a string. An empty string is returned for `null`
|
---|
1916 | * and `undefined` values. The sign of `-0` is preserved.
|
---|
1917 | *
|
---|
1918 | * @static
|
---|
1919 | * @memberOf _
|
---|
1920 | * @since 4.0.0
|
---|
1921 | * @category Lang
|
---|
1922 | * @param {*} value The value to convert.
|
---|
1923 | * @returns {string} Returns the converted string.
|
---|
1924 | * @example
|
---|
1925 | *
|
---|
1926 | * _.toString(null);
|
---|
1927 | * // => ''
|
---|
1928 | *
|
---|
1929 | * _.toString(-0);
|
---|
1930 | * // => '-0'
|
---|
1931 | *
|
---|
1932 | * _.toString([1, 2, 3]);
|
---|
1933 | * // => '1,2,3'
|
---|
1934 | */
|
---|
1935 | function toString(value) {
|
---|
1936 | return value == null ? '' : baseToString(value);
|
---|
1937 | }
|
---|
1938 |
|
---|
1939 | /** Used to match leading and trailing whitespace. */
|
---|
1940 | var reTrim = /^\s+|\s+$/g;
|
---|
1941 |
|
---|
1942 | /**
|
---|
1943 | * Removes leading and trailing whitespace or specified characters from `string`.
|
---|
1944 | *
|
---|
1945 | * @static
|
---|
1946 | * @memberOf _
|
---|
1947 | * @since 3.0.0
|
---|
1948 | * @category String
|
---|
1949 | * @param {string} [string=''] The string to trim.
|
---|
1950 | * @param {string} [chars=whitespace] The characters to trim.
|
---|
1951 | * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
---|
1952 | * @returns {string} Returns the trimmed string.
|
---|
1953 | * @example
|
---|
1954 | *
|
---|
1955 | * _.trim(' abc ');
|
---|
1956 | * // => 'abc'
|
---|
1957 | *
|
---|
1958 | * _.trim('-_-abc-_-', '_-');
|
---|
1959 | * // => 'abc'
|
---|
1960 | *
|
---|
1961 | * _.map([' foo ', ' bar '], _.trim);
|
---|
1962 | * // => ['foo', 'bar']
|
---|
1963 | */
|
---|
1964 | function trim(string, chars, guard) {
|
---|
1965 | string = toString(string);
|
---|
1966 | if (string && (guard || chars === undefined)) {
|
---|
1967 | return string.replace(reTrim, '');
|
---|
1968 | }
|
---|
1969 | if (!string || !(chars = baseToString(chars))) {
|
---|
1970 | return string;
|
---|
1971 | }
|
---|
1972 | var strSymbols = stringToArray(string),
|
---|
1973 | chrSymbols = stringToArray(chars),
|
---|
1974 | start = charsStartIndex(strSymbols, chrSymbols),
|
---|
1975 | end = charsEndIndex(strSymbols, chrSymbols) + 1;
|
---|
1976 |
|
---|
1977 | return castSlice(strSymbols, start, end).join('');
|
---|
1978 | }
|
---|
1979 |
|
---|
1980 | var FN_ARGS = /^(?:async\s+)?(function)?\s*[^\(]*\(\s*([^\)]*)\)/m;
|
---|
1981 | var FN_ARG_SPLIT = /,/;
|
---|
1982 | var FN_ARG = /(=.+)?(\s*)$/;
|
---|
1983 | var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
---|
1984 |
|
---|
1985 | function parseParams(func) {
|
---|
1986 | func = func.toString().replace(STRIP_COMMENTS, '');
|
---|
1987 | func = func.match(FN_ARGS)[2].replace(' ', '');
|
---|
1988 | func = func ? func.split(FN_ARG_SPLIT) : [];
|
---|
1989 | func = func.map(function (arg){
|
---|
1990 | return trim(arg.replace(FN_ARG, ''));
|
---|
1991 | });
|
---|
1992 | return func;
|
---|
1993 | }
|
---|
1994 |
|
---|
1995 | /**
|
---|
1996 | * A dependency-injected version of the [async.auto]{@link module:ControlFlow.auto} function. Dependent
|
---|
1997 | * tasks are specified as parameters to the function, after the usual callback
|
---|
1998 | * parameter, with the parameter names matching the names of the tasks it
|
---|
1999 | * depends on. This can provide even more readable task graphs which can be
|
---|
2000 | * easier to maintain.
|
---|
2001 | *
|
---|
2002 | * If a final callback is specified, the task results are similarly injected,
|
---|
2003 | * specified as named parameters after the initial error parameter.
|
---|
2004 | *
|
---|
2005 | * The autoInject function is purely syntactic sugar and its semantics are
|
---|
2006 | * otherwise equivalent to [async.auto]{@link module:ControlFlow.auto}.
|
---|
2007 | *
|
---|
2008 | * @name autoInject
|
---|
2009 | * @static
|
---|
2010 | * @memberOf module:ControlFlow
|
---|
2011 | * @method
|
---|
2012 | * @see [async.auto]{@link module:ControlFlow.auto}
|
---|
2013 | * @category Control Flow
|
---|
2014 | * @param {Object} tasks - An object, each of whose properties is an {@link AsyncFunction} of
|
---|
2015 | * the form 'func([dependencies...], callback). The object's key of a property
|
---|
2016 | * serves as the name of the task defined by that property, i.e. can be used
|
---|
2017 | * when specifying requirements for other tasks.
|
---|
2018 | * * The `callback` parameter is a `callback(err, result)` which must be called
|
---|
2019 | * when finished, passing an `error` (which can be `null`) and the result of
|
---|
2020 | * the function's execution. The remaining parameters name other tasks on
|
---|
2021 | * which the task is dependent, and the results from those tasks are the
|
---|
2022 | * arguments of those parameters.
|
---|
2023 | * @param {Function} [callback] - An optional callback which is called when all
|
---|
2024 | * the tasks have been completed. It receives the `err` argument if any `tasks`
|
---|
2025 | * pass an error to their callback, and a `results` object with any completed
|
---|
2026 | * task results, similar to `auto`.
|
---|
2027 | * @example
|
---|
2028 | *
|
---|
2029 | * // The example from `auto` can be rewritten as follows:
|
---|
2030 | * async.autoInject({
|
---|
2031 | * get_data: function(callback) {
|
---|
2032 | * // async code to get some data
|
---|
2033 | * callback(null, 'data', 'converted to array');
|
---|
2034 | * },
|
---|
2035 | * make_folder: function(callback) {
|
---|
2036 | * // async code to create a directory to store a file in
|
---|
2037 | * // this is run at the same time as getting the data
|
---|
2038 | * callback(null, 'folder');
|
---|
2039 | * },
|
---|
2040 | * write_file: function(get_data, make_folder, callback) {
|
---|
2041 | * // once there is some data and the directory exists,
|
---|
2042 | * // write the data to a file in the directory
|
---|
2043 | * callback(null, 'filename');
|
---|
2044 | * },
|
---|
2045 | * email_link: function(write_file, callback) {
|
---|
2046 | * // once the file is written let's email a link to it...
|
---|
2047 | * // write_file contains the filename returned by write_file.
|
---|
2048 | * callback(null, {'file':write_file, 'email':'user@example.com'});
|
---|
2049 | * }
|
---|
2050 | * }, function(err, results) {
|
---|
2051 | * console.log('err = ', err);
|
---|
2052 | * console.log('email_link = ', results.email_link);
|
---|
2053 | * });
|
---|
2054 | *
|
---|
2055 | * // If you are using a JS minifier that mangles parameter names, `autoInject`
|
---|
2056 | * // will not work with plain functions, since the parameter names will be
|
---|
2057 | * // collapsed to a single letter identifier. To work around this, you can
|
---|
2058 | * // explicitly specify the names of the parameters your task function needs
|
---|
2059 | * // in an array, similar to Angular.js dependency injection.
|
---|
2060 | *
|
---|
2061 | * // This still has an advantage over plain `auto`, since the results a task
|
---|
2062 | * // depends on are still spread into arguments.
|
---|
2063 | * async.autoInject({
|
---|
2064 | * //...
|
---|
2065 | * write_file: ['get_data', 'make_folder', function(get_data, make_folder, callback) {
|
---|
2066 | * callback(null, 'filename');
|
---|
2067 | * }],
|
---|
2068 | * email_link: ['write_file', function(write_file, callback) {
|
---|
2069 | * callback(null, {'file':write_file, 'email':'user@example.com'});
|
---|
2070 | * }]
|
---|
2071 | * //...
|
---|
2072 | * }, function(err, results) {
|
---|
2073 | * console.log('err = ', err);
|
---|
2074 | * console.log('email_link = ', results.email_link);
|
---|
2075 | * });
|
---|
2076 | */
|
---|
2077 | function autoInject(tasks, callback) {
|
---|
2078 | var newTasks = {};
|
---|
2079 |
|
---|
2080 | baseForOwn(tasks, function (taskFn, key) {
|
---|
2081 | var params;
|
---|
2082 | var fnIsAsync = isAsync(taskFn);
|
---|
2083 | var hasNoDeps =
|
---|
2084 | (!fnIsAsync && taskFn.length === 1) ||
|
---|
2085 | (fnIsAsync && taskFn.length === 0);
|
---|
2086 |
|
---|
2087 | if (isArray(taskFn)) {
|
---|
2088 | params = taskFn.slice(0, -1);
|
---|
2089 | taskFn = taskFn[taskFn.length - 1];
|
---|
2090 |
|
---|
2091 | newTasks[key] = params.concat(params.length > 0 ? newTask : taskFn);
|
---|
2092 | } else if (hasNoDeps) {
|
---|
2093 | // no dependencies, use the function as-is
|
---|
2094 | newTasks[key] = taskFn;
|
---|
2095 | } else {
|
---|
2096 | params = parseParams(taskFn);
|
---|
2097 | if (taskFn.length === 0 && !fnIsAsync && params.length === 0) {
|
---|
2098 | throw new Error("autoInject task functions require explicit parameters.");
|
---|
2099 | }
|
---|
2100 |
|
---|
2101 | // remove callback param
|
---|
2102 | if (!fnIsAsync) params.pop();
|
---|
2103 |
|
---|
2104 | newTasks[key] = params.concat(newTask);
|
---|
2105 | }
|
---|
2106 |
|
---|
2107 | function newTask(results, taskCb) {
|
---|
2108 | var newArgs = arrayMap(params, function (name) {
|
---|
2109 | return results[name];
|
---|
2110 | });
|
---|
2111 | newArgs.push(taskCb);
|
---|
2112 | wrapAsync(taskFn).apply(null, newArgs);
|
---|
2113 | }
|
---|
2114 | });
|
---|
2115 |
|
---|
2116 | auto(newTasks, callback);
|
---|
2117 | }
|
---|
2118 |
|
---|
2119 | // Simple doubly linked list (https://en.wikipedia.org/wiki/Doubly_linked_list) implementation
|
---|
2120 | // used for queues. This implementation assumes that the node provided by the user can be modified
|
---|
2121 | // to adjust the next and last properties. We implement only the minimal functionality
|
---|
2122 | // for queue support.
|
---|
2123 | function DLL() {
|
---|
2124 | this.head = this.tail = null;
|
---|
2125 | this.length = 0;
|
---|
2126 | }
|
---|
2127 |
|
---|
2128 | function setInitial(dll, node) {
|
---|
2129 | dll.length = 1;
|
---|
2130 | dll.head = dll.tail = node;
|
---|
2131 | }
|
---|
2132 |
|
---|
2133 | DLL.prototype.removeLink = function(node) {
|
---|
2134 | if (node.prev) node.prev.next = node.next;
|
---|
2135 | else this.head = node.next;
|
---|
2136 | if (node.next) node.next.prev = node.prev;
|
---|
2137 | else this.tail = node.prev;
|
---|
2138 |
|
---|
2139 | node.prev = node.next = null;
|
---|
2140 | this.length -= 1;
|
---|
2141 | return node;
|
---|
2142 | };
|
---|
2143 |
|
---|
2144 | DLL.prototype.empty = function () {
|
---|
2145 | while(this.head) this.shift();
|
---|
2146 | return this;
|
---|
2147 | };
|
---|
2148 |
|
---|
2149 | DLL.prototype.insertAfter = function(node, newNode) {
|
---|
2150 | newNode.prev = node;
|
---|
2151 | newNode.next = node.next;
|
---|
2152 | if (node.next) node.next.prev = newNode;
|
---|
2153 | else this.tail = newNode;
|
---|
2154 | node.next = newNode;
|
---|
2155 | this.length += 1;
|
---|
2156 | };
|
---|
2157 |
|
---|
2158 | DLL.prototype.insertBefore = function(node, newNode) {
|
---|
2159 | newNode.prev = node.prev;
|
---|
2160 | newNode.next = node;
|
---|
2161 | if (node.prev) node.prev.next = newNode;
|
---|
2162 | else this.head = newNode;
|
---|
2163 | node.prev = newNode;
|
---|
2164 | this.length += 1;
|
---|
2165 | };
|
---|
2166 |
|
---|
2167 | DLL.prototype.unshift = function(node) {
|
---|
2168 | if (this.head) this.insertBefore(this.head, node);
|
---|
2169 | else setInitial(this, node);
|
---|
2170 | };
|
---|
2171 |
|
---|
2172 | DLL.prototype.push = function(node) {
|
---|
2173 | if (this.tail) this.insertAfter(this.tail, node);
|
---|
2174 | else setInitial(this, node);
|
---|
2175 | };
|
---|
2176 |
|
---|
2177 | DLL.prototype.shift = function() {
|
---|
2178 | return this.head && this.removeLink(this.head);
|
---|
2179 | };
|
---|
2180 |
|
---|
2181 | DLL.prototype.pop = function() {
|
---|
2182 | return this.tail && this.removeLink(this.tail);
|
---|
2183 | };
|
---|
2184 |
|
---|
2185 | DLL.prototype.toArray = function () {
|
---|
2186 | var arr = Array(this.length);
|
---|
2187 | var curr = this.head;
|
---|
2188 | for(var idx = 0; idx < this.length; idx++) {
|
---|
2189 | arr[idx] = curr.data;
|
---|
2190 | curr = curr.next;
|
---|
2191 | }
|
---|
2192 | return arr;
|
---|
2193 | };
|
---|
2194 |
|
---|
2195 | DLL.prototype.remove = function (testFn) {
|
---|
2196 | var curr = this.head;
|
---|
2197 | while(!!curr) {
|
---|
2198 | var next = curr.next;
|
---|
2199 | if (testFn(curr)) {
|
---|
2200 | this.removeLink(curr);
|
---|
2201 | }
|
---|
2202 | curr = next;
|
---|
2203 | }
|
---|
2204 | return this;
|
---|
2205 | };
|
---|
2206 |
|
---|
2207 | function queue(worker, concurrency, payload) {
|
---|
2208 | if (concurrency == null) {
|
---|
2209 | concurrency = 1;
|
---|
2210 | }
|
---|
2211 | else if(concurrency === 0) {
|
---|
2212 | throw new Error('Concurrency must not be zero');
|
---|
2213 | }
|
---|
2214 |
|
---|
2215 | var _worker = wrapAsync(worker);
|
---|
2216 | var numRunning = 0;
|
---|
2217 | var workersList = [];
|
---|
2218 |
|
---|
2219 | var processingScheduled = false;
|
---|
2220 | function _insert(data, insertAtFront, callback) {
|
---|
2221 | if (callback != null && typeof callback !== 'function') {
|
---|
2222 | throw new Error('task callback must be a function');
|
---|
2223 | }
|
---|
2224 | q.started = true;
|
---|
2225 | if (!isArray(data)) {
|
---|
2226 | data = [data];
|
---|
2227 | }
|
---|
2228 | if (data.length === 0 && q.idle()) {
|
---|
2229 | // call drain immediately if there are no tasks
|
---|
2230 | return setImmediate$1(function() {
|
---|
2231 | q.drain();
|
---|
2232 | });
|
---|
2233 | }
|
---|
2234 |
|
---|
2235 | for (var i = 0, l = data.length; i < l; i++) {
|
---|
2236 | var item = {
|
---|
2237 | data: data[i],
|
---|
2238 | callback: callback || noop
|
---|
2239 | };
|
---|
2240 |
|
---|
2241 | if (insertAtFront) {
|
---|
2242 | q._tasks.unshift(item);
|
---|
2243 | } else {
|
---|
2244 | q._tasks.push(item);
|
---|
2245 | }
|
---|
2246 | }
|
---|
2247 |
|
---|
2248 | if (!processingScheduled) {
|
---|
2249 | processingScheduled = true;
|
---|
2250 | setImmediate$1(function() {
|
---|
2251 | processingScheduled = false;
|
---|
2252 | q.process();
|
---|
2253 | });
|
---|
2254 | }
|
---|
2255 | }
|
---|
2256 |
|
---|
2257 | function _next(tasks) {
|
---|
2258 | return function(err){
|
---|
2259 | numRunning -= 1;
|
---|
2260 |
|
---|
2261 | for (var i = 0, l = tasks.length; i < l; i++) {
|
---|
2262 | var task = tasks[i];
|
---|
2263 |
|
---|
2264 | var index = baseIndexOf(workersList, task, 0);
|
---|
2265 | if (index === 0) {
|
---|
2266 | workersList.shift();
|
---|
2267 | } else if (index > 0) {
|
---|
2268 | workersList.splice(index, 1);
|
---|
2269 | }
|
---|
2270 |
|
---|
2271 | task.callback.apply(task, arguments);
|
---|
2272 |
|
---|
2273 | if (err != null) {
|
---|
2274 | q.error(err, task.data);
|
---|
2275 | }
|
---|
2276 | }
|
---|
2277 |
|
---|
2278 | if (numRunning <= (q.concurrency - q.buffer) ) {
|
---|
2279 | q.unsaturated();
|
---|
2280 | }
|
---|
2281 |
|
---|
2282 | if (q.idle()) {
|
---|
2283 | q.drain();
|
---|
2284 | }
|
---|
2285 | q.process();
|
---|
2286 | };
|
---|
2287 | }
|
---|
2288 |
|
---|
2289 | var isProcessing = false;
|
---|
2290 | var q = {
|
---|
2291 | _tasks: new DLL(),
|
---|
2292 | concurrency: concurrency,
|
---|
2293 | payload: payload,
|
---|
2294 | saturated: noop,
|
---|
2295 | unsaturated:noop,
|
---|
2296 | buffer: concurrency / 4,
|
---|
2297 | empty: noop,
|
---|
2298 | drain: noop,
|
---|
2299 | error: noop,
|
---|
2300 | started: false,
|
---|
2301 | paused: false,
|
---|
2302 | push: function (data, callback) {
|
---|
2303 | _insert(data, false, callback);
|
---|
2304 | },
|
---|
2305 | kill: function () {
|
---|
2306 | q.drain = noop;
|
---|
2307 | q._tasks.empty();
|
---|
2308 | },
|
---|
2309 | unshift: function (data, callback) {
|
---|
2310 | _insert(data, true, callback);
|
---|
2311 | },
|
---|
2312 | remove: function (testFn) {
|
---|
2313 | q._tasks.remove(testFn);
|
---|
2314 | },
|
---|
2315 | process: function () {
|
---|
2316 | // Avoid trying to start too many processing operations. This can occur
|
---|
2317 | // when callbacks resolve synchronously (#1267).
|
---|
2318 | if (isProcessing) {
|
---|
2319 | return;
|
---|
2320 | }
|
---|
2321 | isProcessing = true;
|
---|
2322 | while(!q.paused && numRunning < q.concurrency && q._tasks.length){
|
---|
2323 | var tasks = [], data = [];
|
---|
2324 | var l = q._tasks.length;
|
---|
2325 | if (q.payload) l = Math.min(l, q.payload);
|
---|
2326 | for (var i = 0; i < l; i++) {
|
---|
2327 | var node = q._tasks.shift();
|
---|
2328 | tasks.push(node);
|
---|
2329 | workersList.push(node);
|
---|
2330 | data.push(node.data);
|
---|
2331 | }
|
---|
2332 |
|
---|
2333 | numRunning += 1;
|
---|
2334 |
|
---|
2335 | if (q._tasks.length === 0) {
|
---|
2336 | q.empty();
|
---|
2337 | }
|
---|
2338 |
|
---|
2339 | if (numRunning === q.concurrency) {
|
---|
2340 | q.saturated();
|
---|
2341 | }
|
---|
2342 |
|
---|
2343 | var cb = onlyOnce(_next(tasks));
|
---|
2344 | _worker(data, cb);
|
---|
2345 | }
|
---|
2346 | isProcessing = false;
|
---|
2347 | },
|
---|
2348 | length: function () {
|
---|
2349 | return q._tasks.length;
|
---|
2350 | },
|
---|
2351 | running: function () {
|
---|
2352 | return numRunning;
|
---|
2353 | },
|
---|
2354 | workersList: function () {
|
---|
2355 | return workersList;
|
---|
2356 | },
|
---|
2357 | idle: function() {
|
---|
2358 | return q._tasks.length + numRunning === 0;
|
---|
2359 | },
|
---|
2360 | pause: function () {
|
---|
2361 | q.paused = true;
|
---|
2362 | },
|
---|
2363 | resume: function () {
|
---|
2364 | if (q.paused === false) { return; }
|
---|
2365 | q.paused = false;
|
---|
2366 | setImmediate$1(q.process);
|
---|
2367 | }
|
---|
2368 | };
|
---|
2369 | return q;
|
---|
2370 | }
|
---|
2371 |
|
---|
2372 | /**
|
---|
2373 | * A cargo of tasks for the worker function to complete. Cargo inherits all of
|
---|
2374 | * the same methods and event callbacks as [`queue`]{@link module:ControlFlow.queue}.
|
---|
2375 | * @typedef {Object} CargoObject
|
---|
2376 | * @memberOf module:ControlFlow
|
---|
2377 | * @property {Function} length - A function returning the number of items
|
---|
2378 | * waiting to be processed. Invoke like `cargo.length()`.
|
---|
2379 | * @property {number} payload - An `integer` for determining how many tasks
|
---|
2380 | * should be process per round. This property can be changed after a `cargo` is
|
---|
2381 | * created to alter the payload on-the-fly.
|
---|
2382 | * @property {Function} push - Adds `task` to the `queue`. The callback is
|
---|
2383 | * called once the `worker` has finished processing the task. Instead of a
|
---|
2384 | * single task, an array of `tasks` can be submitted. The respective callback is
|
---|
2385 | * used for every task in the list. Invoke like `cargo.push(task, [callback])`.
|
---|
2386 | * @property {Function} saturated - A callback that is called when the
|
---|
2387 | * `queue.length()` hits the concurrency and further tasks will be queued.
|
---|
2388 | * @property {Function} empty - A callback that is called when the last item
|
---|
2389 | * from the `queue` is given to a `worker`.
|
---|
2390 | * @property {Function} drain - A callback that is called when the last item
|
---|
2391 | * from the `queue` has returned from the `worker`.
|
---|
2392 | * @property {Function} idle - a function returning false if there are items
|
---|
2393 | * waiting or being processed, or true if not. Invoke like `cargo.idle()`.
|
---|
2394 | * @property {Function} pause - a function that pauses the processing of tasks
|
---|
2395 | * until `resume()` is called. Invoke like `cargo.pause()`.
|
---|
2396 | * @property {Function} resume - a function that resumes the processing of
|
---|
2397 | * queued tasks when the queue is paused. Invoke like `cargo.resume()`.
|
---|
2398 | * @property {Function} kill - a function that removes the `drain` callback and
|
---|
2399 | * empties remaining tasks from the queue forcing it to go idle. Invoke like `cargo.kill()`.
|
---|
2400 | */
|
---|
2401 |
|
---|
2402 | /**
|
---|
2403 | * Creates a `cargo` object with the specified payload. Tasks added to the
|
---|
2404 | * cargo will be processed altogether (up to the `payload` limit). If the
|
---|
2405 | * `worker` is in progress, the task is queued until it becomes available. Once
|
---|
2406 | * the `worker` has completed some tasks, each callback of those tasks is
|
---|
2407 | * called. Check out [these](https://camo.githubusercontent.com/6bbd36f4cf5b35a0f11a96dcd2e97711ffc2fb37/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130382f62626330636662302d356632392d313165322d393734662d3333393763363464633835382e676966) [animations](https://camo.githubusercontent.com/f4810e00e1c5f5f8addbe3e9f49064fd5d102699/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130312f38346339323036362d356632392d313165322d383134662d3964336430323431336266642e676966)
|
---|
2408 | * for how `cargo` and `queue` work.
|
---|
2409 | *
|
---|
2410 | * While [`queue`]{@link module:ControlFlow.queue} passes only one task to one of a group of workers
|
---|
2411 | * at a time, cargo passes an array of tasks to a single worker, repeating
|
---|
2412 | * when the worker is finished.
|
---|
2413 | *
|
---|
2414 | * @name cargo
|
---|
2415 | * @static
|
---|
2416 | * @memberOf module:ControlFlow
|
---|
2417 | * @method
|
---|
2418 | * @see [async.queue]{@link module:ControlFlow.queue}
|
---|
2419 | * @category Control Flow
|
---|
2420 | * @param {AsyncFunction} worker - An asynchronous function for processing an array
|
---|
2421 | * of queued tasks. Invoked with `(tasks, callback)`.
|
---|
2422 | * @param {number} [payload=Infinity] - An optional `integer` for determining
|
---|
2423 | * how many tasks should be processed per round; if omitted, the default is
|
---|
2424 | * unlimited.
|
---|
2425 | * @returns {module:ControlFlow.CargoObject} A cargo object to manage the tasks. Callbacks can
|
---|
2426 | * attached as certain properties to listen for specific events during the
|
---|
2427 | * lifecycle of the cargo and inner queue.
|
---|
2428 | * @example
|
---|
2429 | *
|
---|
2430 | * // create a cargo object with payload 2
|
---|
2431 | * var cargo = async.cargo(function(tasks, callback) {
|
---|
2432 | * for (var i=0; i<tasks.length; i++) {
|
---|
2433 | * console.log('hello ' + tasks[i].name);
|
---|
2434 | * }
|
---|
2435 | * callback();
|
---|
2436 | * }, 2);
|
---|
2437 | *
|
---|
2438 | * // add some items
|
---|
2439 | * cargo.push({name: 'foo'}, function(err) {
|
---|
2440 | * console.log('finished processing foo');
|
---|
2441 | * });
|
---|
2442 | * cargo.push({name: 'bar'}, function(err) {
|
---|
2443 | * console.log('finished processing bar');
|
---|
2444 | * });
|
---|
2445 | * cargo.push({name: 'baz'}, function(err) {
|
---|
2446 | * console.log('finished processing baz');
|
---|
2447 | * });
|
---|
2448 | */
|
---|
2449 | function cargo(worker, payload) {
|
---|
2450 | return queue(worker, 1, payload);
|
---|
2451 | }
|
---|
2452 |
|
---|
2453 | /**
|
---|
2454 | * The same as [`eachOf`]{@link module:Collections.eachOf} but runs only a single async operation at a time.
|
---|
2455 | *
|
---|
2456 | * @name eachOfSeries
|
---|
2457 | * @static
|
---|
2458 | * @memberOf module:Collections
|
---|
2459 | * @method
|
---|
2460 | * @see [async.eachOf]{@link module:Collections.eachOf}
|
---|
2461 | * @alias forEachOfSeries
|
---|
2462 | * @category Collection
|
---|
2463 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
2464 | * @param {AsyncFunction} iteratee - An async function to apply to each item in
|
---|
2465 | * `coll`.
|
---|
2466 | * Invoked with (item, key, callback).
|
---|
2467 | * @param {Function} [callback] - A callback which is called when all `iteratee`
|
---|
2468 | * functions have finished, or an error occurs. Invoked with (err).
|
---|
2469 | */
|
---|
2470 | var eachOfSeries = doLimit(eachOfLimit, 1);
|
---|
2471 |
|
---|
2472 | /**
|
---|
2473 | * Reduces `coll` into a single value using an async `iteratee` to return each
|
---|
2474 | * successive step. `memo` is the initial state of the reduction. This function
|
---|
2475 | * only operates in series.
|
---|
2476 | *
|
---|
2477 | * For performance reasons, it may make sense to split a call to this function
|
---|
2478 | * into a parallel map, and then use the normal `Array.prototype.reduce` on the
|
---|
2479 | * results. This function is for situations where each step in the reduction
|
---|
2480 | * needs to be async; if you can get the data before reducing it, then it's
|
---|
2481 | * probably a good idea to do so.
|
---|
2482 | *
|
---|
2483 | * @name reduce
|
---|
2484 | * @static
|
---|
2485 | * @memberOf module:Collections
|
---|
2486 | * @method
|
---|
2487 | * @alias inject
|
---|
2488 | * @alias foldl
|
---|
2489 | * @category Collection
|
---|
2490 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
2491 | * @param {*} memo - The initial state of the reduction.
|
---|
2492 | * @param {AsyncFunction} iteratee - A function applied to each item in the
|
---|
2493 | * array to produce the next step in the reduction.
|
---|
2494 | * The `iteratee` should complete with the next state of the reduction.
|
---|
2495 | * If the iteratee complete with an error, the reduction is stopped and the
|
---|
2496 | * main `callback` is immediately called with the error.
|
---|
2497 | * Invoked with (memo, item, callback).
|
---|
2498 | * @param {Function} [callback] - A callback which is called after all the
|
---|
2499 | * `iteratee` functions have finished. Result is the reduced value. Invoked with
|
---|
2500 | * (err, result).
|
---|
2501 | * @example
|
---|
2502 | *
|
---|
2503 | * async.reduce([1,2,3], 0, function(memo, item, callback) {
|
---|
2504 | * // pointless async:
|
---|
2505 | * process.nextTick(function() {
|
---|
2506 | * callback(null, memo + item)
|
---|
2507 | * });
|
---|
2508 | * }, function(err, result) {
|
---|
2509 | * // result is now equal to the last value of memo, which is 6
|
---|
2510 | * });
|
---|
2511 | */
|
---|
2512 | function reduce(coll, memo, iteratee, callback) {
|
---|
2513 | callback = once(callback || noop);
|
---|
2514 | var _iteratee = wrapAsync(iteratee);
|
---|
2515 | eachOfSeries(coll, function(x, i, callback) {
|
---|
2516 | _iteratee(memo, x, function(err, v) {
|
---|
2517 | memo = v;
|
---|
2518 | callback(err);
|
---|
2519 | });
|
---|
2520 | }, function(err) {
|
---|
2521 | callback(err, memo);
|
---|
2522 | });
|
---|
2523 | }
|
---|
2524 |
|
---|
2525 | /**
|
---|
2526 | * Version of the compose function that is more natural to read. Each function
|
---|
2527 | * consumes the return value of the previous function. It is the equivalent of
|
---|
2528 | * [compose]{@link module:ControlFlow.compose} with the arguments reversed.
|
---|
2529 | *
|
---|
2530 | * Each function is executed with the `this` binding of the composed function.
|
---|
2531 | *
|
---|
2532 | * @name seq
|
---|
2533 | * @static
|
---|
2534 | * @memberOf module:ControlFlow
|
---|
2535 | * @method
|
---|
2536 | * @see [async.compose]{@link module:ControlFlow.compose}
|
---|
2537 | * @category Control Flow
|
---|
2538 | * @param {...AsyncFunction} functions - the asynchronous functions to compose
|
---|
2539 | * @returns {Function} a function that composes the `functions` in order
|
---|
2540 | * @example
|
---|
2541 | *
|
---|
2542 | * // Requires lodash (or underscore), express3 and dresende's orm2.
|
---|
2543 | * // Part of an app, that fetches cats of the logged user.
|
---|
2544 | * // This example uses `seq` function to avoid overnesting and error
|
---|
2545 | * // handling clutter.
|
---|
2546 | * app.get('/cats', function(request, response) {
|
---|
2547 | * var User = request.models.User;
|
---|
2548 | * async.seq(
|
---|
2549 | * _.bind(User.get, User), // 'User.get' has signature (id, callback(err, data))
|
---|
2550 | * function(user, fn) {
|
---|
2551 | * user.getCats(fn); // 'getCats' has signature (callback(err, data))
|
---|
2552 | * }
|
---|
2553 | * )(req.session.user_id, function (err, cats) {
|
---|
2554 | * if (err) {
|
---|
2555 | * console.error(err);
|
---|
2556 | * response.json({ status: 'error', message: err.message });
|
---|
2557 | * } else {
|
---|
2558 | * response.json({ status: 'ok', message: 'Cats found', data: cats });
|
---|
2559 | * }
|
---|
2560 | * });
|
---|
2561 | * });
|
---|
2562 | */
|
---|
2563 | function seq(/*...functions*/) {
|
---|
2564 | var _functions = arrayMap(arguments, wrapAsync);
|
---|
2565 | return function(/*...args*/) {
|
---|
2566 | var args = slice(arguments);
|
---|
2567 | var that = this;
|
---|
2568 |
|
---|
2569 | var cb = args[args.length - 1];
|
---|
2570 | if (typeof cb == 'function') {
|
---|
2571 | args.pop();
|
---|
2572 | } else {
|
---|
2573 | cb = noop;
|
---|
2574 | }
|
---|
2575 |
|
---|
2576 | reduce(_functions, args, function(newargs, fn, cb) {
|
---|
2577 | fn.apply(that, newargs.concat(function(err/*, ...nextargs*/) {
|
---|
2578 | var nextargs = slice(arguments, 1);
|
---|
2579 | cb(err, nextargs);
|
---|
2580 | }));
|
---|
2581 | },
|
---|
2582 | function(err, results) {
|
---|
2583 | cb.apply(that, [err].concat(results));
|
---|
2584 | });
|
---|
2585 | };
|
---|
2586 | }
|
---|
2587 |
|
---|
2588 | /**
|
---|
2589 | * Creates a function which is a composition of the passed asynchronous
|
---|
2590 | * functions. Each function consumes the return value of the function that
|
---|
2591 | * follows. Composing functions `f()`, `g()`, and `h()` would produce the result
|
---|
2592 | * of `f(g(h()))`, only this version uses callbacks to obtain the return values.
|
---|
2593 | *
|
---|
2594 | * Each function is executed with the `this` binding of the composed function.
|
---|
2595 | *
|
---|
2596 | * @name compose
|
---|
2597 | * @static
|
---|
2598 | * @memberOf module:ControlFlow
|
---|
2599 | * @method
|
---|
2600 | * @category Control Flow
|
---|
2601 | * @param {...AsyncFunction} functions - the asynchronous functions to compose
|
---|
2602 | * @returns {Function} an asynchronous function that is the composed
|
---|
2603 | * asynchronous `functions`
|
---|
2604 | * @example
|
---|
2605 | *
|
---|
2606 | * function add1(n, callback) {
|
---|
2607 | * setTimeout(function () {
|
---|
2608 | * callback(null, n + 1);
|
---|
2609 | * }, 10);
|
---|
2610 | * }
|
---|
2611 | *
|
---|
2612 | * function mul3(n, callback) {
|
---|
2613 | * setTimeout(function () {
|
---|
2614 | * callback(null, n * 3);
|
---|
2615 | * }, 10);
|
---|
2616 | * }
|
---|
2617 | *
|
---|
2618 | * var add1mul3 = async.compose(mul3, add1);
|
---|
2619 | * add1mul3(4, function (err, result) {
|
---|
2620 | * // result now equals 15
|
---|
2621 | * });
|
---|
2622 | */
|
---|
2623 | var compose = function(/*...args*/) {
|
---|
2624 | return seq.apply(null, slice(arguments).reverse());
|
---|
2625 | };
|
---|
2626 |
|
---|
2627 | var _concat = Array.prototype.concat;
|
---|
2628 |
|
---|
2629 | /**
|
---|
2630 | * The same as [`concat`]{@link module:Collections.concat} but runs a maximum of `limit` async operations at a time.
|
---|
2631 | *
|
---|
2632 | * @name concatLimit
|
---|
2633 | * @static
|
---|
2634 | * @memberOf module:Collections
|
---|
2635 | * @method
|
---|
2636 | * @see [async.concat]{@link module:Collections.concat}
|
---|
2637 | * @category Collection
|
---|
2638 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
2639 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
2640 | * @param {AsyncFunction} iteratee - A function to apply to each item in `coll`,
|
---|
2641 | * which should use an array as its result. Invoked with (item, callback).
|
---|
2642 | * @param {Function} [callback] - A callback which is called after all the
|
---|
2643 | * `iteratee` functions have finished, or an error occurs. Results is an array
|
---|
2644 | * containing the concatenated results of the `iteratee` function. Invoked with
|
---|
2645 | * (err, results).
|
---|
2646 | */
|
---|
2647 | var concatLimit = function(coll, limit, iteratee, callback) {
|
---|
2648 | callback = callback || noop;
|
---|
2649 | var _iteratee = wrapAsync(iteratee);
|
---|
2650 | mapLimit(coll, limit, function(val, callback) {
|
---|
2651 | _iteratee(val, function(err /*, ...args*/) {
|
---|
2652 | if (err) return callback(err);
|
---|
2653 | return callback(null, slice(arguments, 1));
|
---|
2654 | });
|
---|
2655 | }, function(err, mapResults) {
|
---|
2656 | var result = [];
|
---|
2657 | for (var i = 0; i < mapResults.length; i++) {
|
---|
2658 | if (mapResults[i]) {
|
---|
2659 | result = _concat.apply(result, mapResults[i]);
|
---|
2660 | }
|
---|
2661 | }
|
---|
2662 |
|
---|
2663 | return callback(err, result);
|
---|
2664 | });
|
---|
2665 | };
|
---|
2666 |
|
---|
2667 | /**
|
---|
2668 | * Applies `iteratee` to each item in `coll`, concatenating the results. Returns
|
---|
2669 | * the concatenated list. The `iteratee`s are called in parallel, and the
|
---|
2670 | * results are concatenated as they return. There is no guarantee that the
|
---|
2671 | * results array will be returned in the original order of `coll` passed to the
|
---|
2672 | * `iteratee` function.
|
---|
2673 | *
|
---|
2674 | * @name concat
|
---|
2675 | * @static
|
---|
2676 | * @memberOf module:Collections
|
---|
2677 | * @method
|
---|
2678 | * @category Collection
|
---|
2679 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
2680 | * @param {AsyncFunction} iteratee - A function to apply to each item in `coll`,
|
---|
2681 | * which should use an array as its result. Invoked with (item, callback).
|
---|
2682 | * @param {Function} [callback(err)] - A callback which is called after all the
|
---|
2683 | * `iteratee` functions have finished, or an error occurs. Results is an array
|
---|
2684 | * containing the concatenated results of the `iteratee` function. Invoked with
|
---|
2685 | * (err, results).
|
---|
2686 | * @example
|
---|
2687 | *
|
---|
2688 | * async.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files) {
|
---|
2689 | * // files is now a list of filenames that exist in the 3 directories
|
---|
2690 | * });
|
---|
2691 | */
|
---|
2692 | var concat = doLimit(concatLimit, Infinity);
|
---|
2693 |
|
---|
2694 | /**
|
---|
2695 | * The same as [`concat`]{@link module:Collections.concat} but runs only a single async operation at a time.
|
---|
2696 | *
|
---|
2697 | * @name concatSeries
|
---|
2698 | * @static
|
---|
2699 | * @memberOf module:Collections
|
---|
2700 | * @method
|
---|
2701 | * @see [async.concat]{@link module:Collections.concat}
|
---|
2702 | * @category Collection
|
---|
2703 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
2704 | * @param {AsyncFunction} iteratee - A function to apply to each item in `coll`.
|
---|
2705 | * The iteratee should complete with an array an array of results.
|
---|
2706 | * Invoked with (item, callback).
|
---|
2707 | * @param {Function} [callback(err)] - A callback which is called after all the
|
---|
2708 | * `iteratee` functions have finished, or an error occurs. Results is an array
|
---|
2709 | * containing the concatenated results of the `iteratee` function. Invoked with
|
---|
2710 | * (err, results).
|
---|
2711 | */
|
---|
2712 | var concatSeries = doLimit(concatLimit, 1);
|
---|
2713 |
|
---|
2714 | /**
|
---|
2715 | * Returns a function that when called, calls-back with the values provided.
|
---|
2716 | * Useful as the first function in a [`waterfall`]{@link module:ControlFlow.waterfall}, or for plugging values in to
|
---|
2717 | * [`auto`]{@link module:ControlFlow.auto}.
|
---|
2718 | *
|
---|
2719 | * @name constant
|
---|
2720 | * @static
|
---|
2721 | * @memberOf module:Utils
|
---|
2722 | * @method
|
---|
2723 | * @category Util
|
---|
2724 | * @param {...*} arguments... - Any number of arguments to automatically invoke
|
---|
2725 | * callback with.
|
---|
2726 | * @returns {AsyncFunction} Returns a function that when invoked, automatically
|
---|
2727 | * invokes the callback with the previous given arguments.
|
---|
2728 | * @example
|
---|
2729 | *
|
---|
2730 | * async.waterfall([
|
---|
2731 | * async.constant(42),
|
---|
2732 | * function (value, next) {
|
---|
2733 | * // value === 42
|
---|
2734 | * },
|
---|
2735 | * //...
|
---|
2736 | * ], callback);
|
---|
2737 | *
|
---|
2738 | * async.waterfall([
|
---|
2739 | * async.constant(filename, "utf8"),
|
---|
2740 | * fs.readFile,
|
---|
2741 | * function (fileData, next) {
|
---|
2742 | * //...
|
---|
2743 | * }
|
---|
2744 | * //...
|
---|
2745 | * ], callback);
|
---|
2746 | *
|
---|
2747 | * async.auto({
|
---|
2748 | * hostname: async.constant("https://server.net/"),
|
---|
2749 | * port: findFreePort,
|
---|
2750 | * launchServer: ["hostname", "port", function (options, cb) {
|
---|
2751 | * startServer(options, cb);
|
---|
2752 | * }],
|
---|
2753 | * //...
|
---|
2754 | * }, callback);
|
---|
2755 | */
|
---|
2756 | var constant = function(/*...values*/) {
|
---|
2757 | var values = slice(arguments);
|
---|
2758 | var args = [null].concat(values);
|
---|
2759 | return function (/*...ignoredArgs, callback*/) {
|
---|
2760 | var callback = arguments[arguments.length - 1];
|
---|
2761 | return callback.apply(this, args);
|
---|
2762 | };
|
---|
2763 | };
|
---|
2764 |
|
---|
2765 | /**
|
---|
2766 | * This method returns the first argument it receives.
|
---|
2767 | *
|
---|
2768 | * @static
|
---|
2769 | * @since 0.1.0
|
---|
2770 | * @memberOf _
|
---|
2771 | * @category Util
|
---|
2772 | * @param {*} value Any value.
|
---|
2773 | * @returns {*} Returns `value`.
|
---|
2774 | * @example
|
---|
2775 | *
|
---|
2776 | * var object = { 'a': 1 };
|
---|
2777 | *
|
---|
2778 | * console.log(_.identity(object) === object);
|
---|
2779 | * // => true
|
---|
2780 | */
|
---|
2781 | function identity(value) {
|
---|
2782 | return value;
|
---|
2783 | }
|
---|
2784 |
|
---|
2785 | function _createTester(check, getResult) {
|
---|
2786 | return function(eachfn, arr, iteratee, cb) {
|
---|
2787 | cb = cb || noop;
|
---|
2788 | var testPassed = false;
|
---|
2789 | var testResult;
|
---|
2790 | eachfn(arr, function(value, _, callback) {
|
---|
2791 | iteratee(value, function(err, result) {
|
---|
2792 | if (err) {
|
---|
2793 | callback(err);
|
---|
2794 | } else if (check(result) && !testResult) {
|
---|
2795 | testPassed = true;
|
---|
2796 | testResult = getResult(true, value);
|
---|
2797 | callback(null, breakLoop);
|
---|
2798 | } else {
|
---|
2799 | callback();
|
---|
2800 | }
|
---|
2801 | });
|
---|
2802 | }, function(err) {
|
---|
2803 | if (err) {
|
---|
2804 | cb(err);
|
---|
2805 | } else {
|
---|
2806 | cb(null, testPassed ? testResult : getResult(false));
|
---|
2807 | }
|
---|
2808 | });
|
---|
2809 | };
|
---|
2810 | }
|
---|
2811 |
|
---|
2812 | function _findGetResult(v, x) {
|
---|
2813 | return x;
|
---|
2814 | }
|
---|
2815 |
|
---|
2816 | /**
|
---|
2817 | * Returns the first value in `coll` that passes an async truth test. The
|
---|
2818 | * `iteratee` is applied in parallel, meaning the first iteratee to return
|
---|
2819 | * `true` will fire the detect `callback` with that result. That means the
|
---|
2820 | * result might not be the first item in the original `coll` (in terms of order)
|
---|
2821 | * that passes the test.
|
---|
2822 |
|
---|
2823 | * If order within the original `coll` is important, then look at
|
---|
2824 | * [`detectSeries`]{@link module:Collections.detectSeries}.
|
---|
2825 | *
|
---|
2826 | * @name detect
|
---|
2827 | * @static
|
---|
2828 | * @memberOf module:Collections
|
---|
2829 | * @method
|
---|
2830 | * @alias find
|
---|
2831 | * @category Collections
|
---|
2832 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
2833 | * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.
|
---|
2834 | * The iteratee must complete with a boolean value as its result.
|
---|
2835 | * Invoked with (item, callback).
|
---|
2836 | * @param {Function} [callback] - A callback which is called as soon as any
|
---|
2837 | * iteratee returns `true`, or after all the `iteratee` functions have finished.
|
---|
2838 | * Result will be the first item in the array that passes the truth test
|
---|
2839 | * (iteratee) or the value `undefined` if none passed. Invoked with
|
---|
2840 | * (err, result).
|
---|
2841 | * @example
|
---|
2842 | *
|
---|
2843 | * async.detect(['file1','file2','file3'], function(filePath, callback) {
|
---|
2844 | * fs.access(filePath, function(err) {
|
---|
2845 | * callback(null, !err)
|
---|
2846 | * });
|
---|
2847 | * }, function(err, result) {
|
---|
2848 | * // result now equals the first file in the list that exists
|
---|
2849 | * });
|
---|
2850 | */
|
---|
2851 | var detect = doParallel(_createTester(identity, _findGetResult));
|
---|
2852 |
|
---|
2853 | /**
|
---|
2854 | * The same as [`detect`]{@link module:Collections.detect} but runs a maximum of `limit` async operations at a
|
---|
2855 | * time.
|
---|
2856 | *
|
---|
2857 | * @name detectLimit
|
---|
2858 | * @static
|
---|
2859 | * @memberOf module:Collections
|
---|
2860 | * @method
|
---|
2861 | * @see [async.detect]{@link module:Collections.detect}
|
---|
2862 | * @alias findLimit
|
---|
2863 | * @category Collections
|
---|
2864 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
2865 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
2866 | * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.
|
---|
2867 | * The iteratee must complete with a boolean value as its result.
|
---|
2868 | * Invoked with (item, callback).
|
---|
2869 | * @param {Function} [callback] - A callback which is called as soon as any
|
---|
2870 | * iteratee returns `true`, or after all the `iteratee` functions have finished.
|
---|
2871 | * Result will be the first item in the array that passes the truth test
|
---|
2872 | * (iteratee) or the value `undefined` if none passed. Invoked with
|
---|
2873 | * (err, result).
|
---|
2874 | */
|
---|
2875 | var detectLimit = doParallelLimit(_createTester(identity, _findGetResult));
|
---|
2876 |
|
---|
2877 | /**
|
---|
2878 | * The same as [`detect`]{@link module:Collections.detect} but runs only a single async operation at a time.
|
---|
2879 | *
|
---|
2880 | * @name detectSeries
|
---|
2881 | * @static
|
---|
2882 | * @memberOf module:Collections
|
---|
2883 | * @method
|
---|
2884 | * @see [async.detect]{@link module:Collections.detect}
|
---|
2885 | * @alias findSeries
|
---|
2886 | * @category Collections
|
---|
2887 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
2888 | * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.
|
---|
2889 | * The iteratee must complete with a boolean value as its result.
|
---|
2890 | * Invoked with (item, callback).
|
---|
2891 | * @param {Function} [callback] - A callback which is called as soon as any
|
---|
2892 | * iteratee returns `true`, or after all the `iteratee` functions have finished.
|
---|
2893 | * Result will be the first item in the array that passes the truth test
|
---|
2894 | * (iteratee) or the value `undefined` if none passed. Invoked with
|
---|
2895 | * (err, result).
|
---|
2896 | */
|
---|
2897 | var detectSeries = doLimit(detectLimit, 1);
|
---|
2898 |
|
---|
2899 | function consoleFunc(name) {
|
---|
2900 | return function (fn/*, ...args*/) {
|
---|
2901 | var args = slice(arguments, 1);
|
---|
2902 | args.push(function (err/*, ...args*/) {
|
---|
2903 | var args = slice(arguments, 1);
|
---|
2904 | if (typeof console === 'object') {
|
---|
2905 | if (err) {
|
---|
2906 | if (console.error) {
|
---|
2907 | console.error(err);
|
---|
2908 | }
|
---|
2909 | } else if (console[name]) {
|
---|
2910 | arrayEach(args, function (x) {
|
---|
2911 | console[name](x);
|
---|
2912 | });
|
---|
2913 | }
|
---|
2914 | }
|
---|
2915 | });
|
---|
2916 | wrapAsync(fn).apply(null, args);
|
---|
2917 | };
|
---|
2918 | }
|
---|
2919 |
|
---|
2920 | /**
|
---|
2921 | * Logs the result of an [`async` function]{@link AsyncFunction} to the
|
---|
2922 | * `console` using `console.dir` to display the properties of the resulting object.
|
---|
2923 | * Only works in Node.js or in browsers that support `console.dir` and
|
---|
2924 | * `console.error` (such as FF and Chrome).
|
---|
2925 | * If multiple arguments are returned from the async function,
|
---|
2926 | * `console.dir` is called on each argument in order.
|
---|
2927 | *
|
---|
2928 | * @name dir
|
---|
2929 | * @static
|
---|
2930 | * @memberOf module:Utils
|
---|
2931 | * @method
|
---|
2932 | * @category Util
|
---|
2933 | * @param {AsyncFunction} function - The function you want to eventually apply
|
---|
2934 | * all arguments to.
|
---|
2935 | * @param {...*} arguments... - Any number of arguments to apply to the function.
|
---|
2936 | * @example
|
---|
2937 | *
|
---|
2938 | * // in a module
|
---|
2939 | * var hello = function(name, callback) {
|
---|
2940 | * setTimeout(function() {
|
---|
2941 | * callback(null, {hello: name});
|
---|
2942 | * }, 1000);
|
---|
2943 | * };
|
---|
2944 | *
|
---|
2945 | * // in the node repl
|
---|
2946 | * node> async.dir(hello, 'world');
|
---|
2947 | * {hello: 'world'}
|
---|
2948 | */
|
---|
2949 | var dir = consoleFunc('dir');
|
---|
2950 |
|
---|
2951 | /**
|
---|
2952 | * The post-check version of [`during`]{@link module:ControlFlow.during}. To reflect the difference in
|
---|
2953 | * the order of operations, the arguments `test` and `fn` are switched.
|
---|
2954 | *
|
---|
2955 | * Also a version of [`doWhilst`]{@link module:ControlFlow.doWhilst} with asynchronous `test` function.
|
---|
2956 | * @name doDuring
|
---|
2957 | * @static
|
---|
2958 | * @memberOf module:ControlFlow
|
---|
2959 | * @method
|
---|
2960 | * @see [async.during]{@link module:ControlFlow.during}
|
---|
2961 | * @category Control Flow
|
---|
2962 | * @param {AsyncFunction} fn - An async function which is called each time
|
---|
2963 | * `test` passes. Invoked with (callback).
|
---|
2964 | * @param {AsyncFunction} test - asynchronous truth test to perform before each
|
---|
2965 | * execution of `fn`. Invoked with (...args, callback), where `...args` are the
|
---|
2966 | * non-error args from the previous callback of `fn`.
|
---|
2967 | * @param {Function} [callback] - A callback which is called after the test
|
---|
2968 | * function has failed and repeated execution of `fn` has stopped. `callback`
|
---|
2969 | * will be passed an error if one occurred, otherwise `null`.
|
---|
2970 | */
|
---|
2971 | function doDuring(fn, test, callback) {
|
---|
2972 | callback = onlyOnce(callback || noop);
|
---|
2973 | var _fn = wrapAsync(fn);
|
---|
2974 | var _test = wrapAsync(test);
|
---|
2975 |
|
---|
2976 | function next(err/*, ...args*/) {
|
---|
2977 | if (err) return callback(err);
|
---|
2978 | var args = slice(arguments, 1);
|
---|
2979 | args.push(check);
|
---|
2980 | _test.apply(this, args);
|
---|
2981 | }
|
---|
2982 |
|
---|
2983 | function check(err, truth) {
|
---|
2984 | if (err) return callback(err);
|
---|
2985 | if (!truth) return callback(null);
|
---|
2986 | _fn(next);
|
---|
2987 | }
|
---|
2988 |
|
---|
2989 | check(null, true);
|
---|
2990 |
|
---|
2991 | }
|
---|
2992 |
|
---|
2993 | /**
|
---|
2994 | * The post-check version of [`whilst`]{@link module:ControlFlow.whilst}. To reflect the difference in
|
---|
2995 | * the order of operations, the arguments `test` and `iteratee` are switched.
|
---|
2996 | *
|
---|
2997 | * `doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript.
|
---|
2998 | *
|
---|
2999 | * @name doWhilst
|
---|
3000 | * @static
|
---|
3001 | * @memberOf module:ControlFlow
|
---|
3002 | * @method
|
---|
3003 | * @see [async.whilst]{@link module:ControlFlow.whilst}
|
---|
3004 | * @category Control Flow
|
---|
3005 | * @param {AsyncFunction} iteratee - A function which is called each time `test`
|
---|
3006 | * passes. Invoked with (callback).
|
---|
3007 | * @param {Function} test - synchronous truth test to perform after each
|
---|
3008 | * execution of `iteratee`. Invoked with any non-error callback results of
|
---|
3009 | * `iteratee`.
|
---|
3010 | * @param {Function} [callback] - A callback which is called after the test
|
---|
3011 | * function has failed and repeated execution of `iteratee` has stopped.
|
---|
3012 | * `callback` will be passed an error and any arguments passed to the final
|
---|
3013 | * `iteratee`'s callback. Invoked with (err, [results]);
|
---|
3014 | */
|
---|
3015 | function doWhilst(iteratee, test, callback) {
|
---|
3016 | callback = onlyOnce(callback || noop);
|
---|
3017 | var _iteratee = wrapAsync(iteratee);
|
---|
3018 | var next = function(err/*, ...args*/) {
|
---|
3019 | if (err) return callback(err);
|
---|
3020 | var args = slice(arguments, 1);
|
---|
3021 | if (test.apply(this, args)) return _iteratee(next);
|
---|
3022 | callback.apply(null, [null].concat(args));
|
---|
3023 | };
|
---|
3024 | _iteratee(next);
|
---|
3025 | }
|
---|
3026 |
|
---|
3027 | /**
|
---|
3028 | * Like ['doWhilst']{@link module:ControlFlow.doWhilst}, except the `test` is inverted. Note the
|
---|
3029 | * argument ordering differs from `until`.
|
---|
3030 | *
|
---|
3031 | * @name doUntil
|
---|
3032 | * @static
|
---|
3033 | * @memberOf module:ControlFlow
|
---|
3034 | * @method
|
---|
3035 | * @see [async.doWhilst]{@link module:ControlFlow.doWhilst}
|
---|
3036 | * @category Control Flow
|
---|
3037 | * @param {AsyncFunction} iteratee - An async function which is called each time
|
---|
3038 | * `test` fails. Invoked with (callback).
|
---|
3039 | * @param {Function} test - synchronous truth test to perform after each
|
---|
3040 | * execution of `iteratee`. Invoked with any non-error callback results of
|
---|
3041 | * `iteratee`.
|
---|
3042 | * @param {Function} [callback] - A callback which is called after the test
|
---|
3043 | * function has passed and repeated execution of `iteratee` has stopped. `callback`
|
---|
3044 | * will be passed an error and any arguments passed to the final `iteratee`'s
|
---|
3045 | * callback. Invoked with (err, [results]);
|
---|
3046 | */
|
---|
3047 | function doUntil(iteratee, test, callback) {
|
---|
3048 | doWhilst(iteratee, function() {
|
---|
3049 | return !test.apply(this, arguments);
|
---|
3050 | }, callback);
|
---|
3051 | }
|
---|
3052 |
|
---|
3053 | /**
|
---|
3054 | * Like [`whilst`]{@link module:ControlFlow.whilst}, except the `test` is an asynchronous function that
|
---|
3055 | * is passed a callback in the form of `function (err, truth)`. If error is
|
---|
3056 | * passed to `test` or `fn`, the main callback is immediately called with the
|
---|
3057 | * value of the error.
|
---|
3058 | *
|
---|
3059 | * @name during
|
---|
3060 | * @static
|
---|
3061 | * @memberOf module:ControlFlow
|
---|
3062 | * @method
|
---|
3063 | * @see [async.whilst]{@link module:ControlFlow.whilst}
|
---|
3064 | * @category Control Flow
|
---|
3065 | * @param {AsyncFunction} test - asynchronous truth test to perform before each
|
---|
3066 | * execution of `fn`. Invoked with (callback).
|
---|
3067 | * @param {AsyncFunction} fn - An async function which is called each time
|
---|
3068 | * `test` passes. Invoked with (callback).
|
---|
3069 | * @param {Function} [callback] - A callback which is called after the test
|
---|
3070 | * function has failed and repeated execution of `fn` has stopped. `callback`
|
---|
3071 | * will be passed an error, if one occurred, otherwise `null`.
|
---|
3072 | * @example
|
---|
3073 | *
|
---|
3074 | * var count = 0;
|
---|
3075 | *
|
---|
3076 | * async.during(
|
---|
3077 | * function (callback) {
|
---|
3078 | * return callback(null, count < 5);
|
---|
3079 | * },
|
---|
3080 | * function (callback) {
|
---|
3081 | * count++;
|
---|
3082 | * setTimeout(callback, 1000);
|
---|
3083 | * },
|
---|
3084 | * function (err) {
|
---|
3085 | * // 5 seconds have passed
|
---|
3086 | * }
|
---|
3087 | * );
|
---|
3088 | */
|
---|
3089 | function during(test, fn, callback) {
|
---|
3090 | callback = onlyOnce(callback || noop);
|
---|
3091 | var _fn = wrapAsync(fn);
|
---|
3092 | var _test = wrapAsync(test);
|
---|
3093 |
|
---|
3094 | function next(err) {
|
---|
3095 | if (err) return callback(err);
|
---|
3096 | _test(check);
|
---|
3097 | }
|
---|
3098 |
|
---|
3099 | function check(err, truth) {
|
---|
3100 | if (err) return callback(err);
|
---|
3101 | if (!truth) return callback(null);
|
---|
3102 | _fn(next);
|
---|
3103 | }
|
---|
3104 |
|
---|
3105 | _test(check);
|
---|
3106 | }
|
---|
3107 |
|
---|
3108 | function _withoutIndex(iteratee) {
|
---|
3109 | return function (value, index, callback) {
|
---|
3110 | return iteratee(value, callback);
|
---|
3111 | };
|
---|
3112 | }
|
---|
3113 |
|
---|
3114 | /**
|
---|
3115 | * Applies the function `iteratee` to each item in `coll`, in parallel.
|
---|
3116 | * The `iteratee` is called with an item from the list, and a callback for when
|
---|
3117 | * it has finished. If the `iteratee` passes an error to its `callback`, the
|
---|
3118 | * main `callback` (for the `each` function) is immediately called with the
|
---|
3119 | * error.
|
---|
3120 | *
|
---|
3121 | * Note, that since this function applies `iteratee` to each item in parallel,
|
---|
3122 | * there is no guarantee that the iteratee functions will complete in order.
|
---|
3123 | *
|
---|
3124 | * @name each
|
---|
3125 | * @static
|
---|
3126 | * @memberOf module:Collections
|
---|
3127 | * @method
|
---|
3128 | * @alias forEach
|
---|
3129 | * @category Collection
|
---|
3130 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
3131 | * @param {AsyncFunction} iteratee - An async function to apply to
|
---|
3132 | * each item in `coll`. Invoked with (item, callback).
|
---|
3133 | * The array index is not passed to the iteratee.
|
---|
3134 | * If you need the index, use `eachOf`.
|
---|
3135 | * @param {Function} [callback] - A callback which is called when all
|
---|
3136 | * `iteratee` functions have finished, or an error occurs. Invoked with (err).
|
---|
3137 | * @example
|
---|
3138 | *
|
---|
3139 | * // assuming openFiles is an array of file names and saveFile is a function
|
---|
3140 | * // to save the modified contents of that file:
|
---|
3141 | *
|
---|
3142 | * async.each(openFiles, saveFile, function(err){
|
---|
3143 | * // if any of the saves produced an error, err would equal that error
|
---|
3144 | * });
|
---|
3145 | *
|
---|
3146 | * // assuming openFiles is an array of file names
|
---|
3147 | * async.each(openFiles, function(file, callback) {
|
---|
3148 | *
|
---|
3149 | * // Perform operation on file here.
|
---|
3150 | * console.log('Processing file ' + file);
|
---|
3151 | *
|
---|
3152 | * if( file.length > 32 ) {
|
---|
3153 | * console.log('This file name is too long');
|
---|
3154 | * callback('File name too long');
|
---|
3155 | * } else {
|
---|
3156 | * // Do work to process file here
|
---|
3157 | * console.log('File processed');
|
---|
3158 | * callback();
|
---|
3159 | * }
|
---|
3160 | * }, function(err) {
|
---|
3161 | * // if any of the file processing produced an error, err would equal that error
|
---|
3162 | * if( err ) {
|
---|
3163 | * // One of the iterations produced an error.
|
---|
3164 | * // All processing will now stop.
|
---|
3165 | * console.log('A file failed to process');
|
---|
3166 | * } else {
|
---|
3167 | * console.log('All files have been processed successfully');
|
---|
3168 | * }
|
---|
3169 | * });
|
---|
3170 | */
|
---|
3171 | function eachLimit(coll, iteratee, callback) {
|
---|
3172 | eachOf(coll, _withoutIndex(wrapAsync(iteratee)), callback);
|
---|
3173 | }
|
---|
3174 |
|
---|
3175 | /**
|
---|
3176 | * The same as [`each`]{@link module:Collections.each} but runs a maximum of `limit` async operations at a time.
|
---|
3177 | *
|
---|
3178 | * @name eachLimit
|
---|
3179 | * @static
|
---|
3180 | * @memberOf module:Collections
|
---|
3181 | * @method
|
---|
3182 | * @see [async.each]{@link module:Collections.each}
|
---|
3183 | * @alias forEachLimit
|
---|
3184 | * @category Collection
|
---|
3185 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
3186 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
3187 | * @param {AsyncFunction} iteratee - An async function to apply to each item in
|
---|
3188 | * `coll`.
|
---|
3189 | * The array index is not passed to the iteratee.
|
---|
3190 | * If you need the index, use `eachOfLimit`.
|
---|
3191 | * Invoked with (item, callback).
|
---|
3192 | * @param {Function} [callback] - A callback which is called when all
|
---|
3193 | * `iteratee` functions have finished, or an error occurs. Invoked with (err).
|
---|
3194 | */
|
---|
3195 | function eachLimit$1(coll, limit, iteratee, callback) {
|
---|
3196 | _eachOfLimit(limit)(coll, _withoutIndex(wrapAsync(iteratee)), callback);
|
---|
3197 | }
|
---|
3198 |
|
---|
3199 | /**
|
---|
3200 | * The same as [`each`]{@link module:Collections.each} but runs only a single async operation at a time.
|
---|
3201 | *
|
---|
3202 | * @name eachSeries
|
---|
3203 | * @static
|
---|
3204 | * @memberOf module:Collections
|
---|
3205 | * @method
|
---|
3206 | * @see [async.each]{@link module:Collections.each}
|
---|
3207 | * @alias forEachSeries
|
---|
3208 | * @category Collection
|
---|
3209 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
3210 | * @param {AsyncFunction} iteratee - An async function to apply to each
|
---|
3211 | * item in `coll`.
|
---|
3212 | * The array index is not passed to the iteratee.
|
---|
3213 | * If you need the index, use `eachOfSeries`.
|
---|
3214 | * Invoked with (item, callback).
|
---|
3215 | * @param {Function} [callback] - A callback which is called when all
|
---|
3216 | * `iteratee` functions have finished, or an error occurs. Invoked with (err).
|
---|
3217 | */
|
---|
3218 | var eachSeries = doLimit(eachLimit$1, 1);
|
---|
3219 |
|
---|
3220 | /**
|
---|
3221 | * Wrap an async function and ensure it calls its callback on a later tick of
|
---|
3222 | * the event loop. If the function already calls its callback on a next tick,
|
---|
3223 | * no extra deferral is added. This is useful for preventing stack overflows
|
---|
3224 | * (`RangeError: Maximum call stack size exceeded`) and generally keeping
|
---|
3225 | * [Zalgo](http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony)
|
---|
3226 | * contained. ES2017 `async` functions are returned as-is -- they are immune
|
---|
3227 | * to Zalgo's corrupting influences, as they always resolve on a later tick.
|
---|
3228 | *
|
---|
3229 | * @name ensureAsync
|
---|
3230 | * @static
|
---|
3231 | * @memberOf module:Utils
|
---|
3232 | * @method
|
---|
3233 | * @category Util
|
---|
3234 | * @param {AsyncFunction} fn - an async function, one that expects a node-style
|
---|
3235 | * callback as its last argument.
|
---|
3236 | * @returns {AsyncFunction} Returns a wrapped function with the exact same call
|
---|
3237 | * signature as the function passed in.
|
---|
3238 | * @example
|
---|
3239 | *
|
---|
3240 | * function sometimesAsync(arg, callback) {
|
---|
3241 | * if (cache[arg]) {
|
---|
3242 | * return callback(null, cache[arg]); // this would be synchronous!!
|
---|
3243 | * } else {
|
---|
3244 | * doSomeIO(arg, callback); // this IO would be asynchronous
|
---|
3245 | * }
|
---|
3246 | * }
|
---|
3247 | *
|
---|
3248 | * // this has a risk of stack overflows if many results are cached in a row
|
---|
3249 | * async.mapSeries(args, sometimesAsync, done);
|
---|
3250 | *
|
---|
3251 | * // this will defer sometimesAsync's callback if necessary,
|
---|
3252 | * // preventing stack overflows
|
---|
3253 | * async.mapSeries(args, async.ensureAsync(sometimesAsync), done);
|
---|
3254 | */
|
---|
3255 | function ensureAsync(fn) {
|
---|
3256 | if (isAsync(fn)) return fn;
|
---|
3257 | return initialParams(function (args, callback) {
|
---|
3258 | var sync = true;
|
---|
3259 | args.push(function () {
|
---|
3260 | var innerArgs = arguments;
|
---|
3261 | if (sync) {
|
---|
3262 | setImmediate$1(function () {
|
---|
3263 | callback.apply(null, innerArgs);
|
---|
3264 | });
|
---|
3265 | } else {
|
---|
3266 | callback.apply(null, innerArgs);
|
---|
3267 | }
|
---|
3268 | });
|
---|
3269 | fn.apply(this, args);
|
---|
3270 | sync = false;
|
---|
3271 | });
|
---|
3272 | }
|
---|
3273 |
|
---|
3274 | function notId(v) {
|
---|
3275 | return !v;
|
---|
3276 | }
|
---|
3277 |
|
---|
3278 | /**
|
---|
3279 | * Returns `true` if every element in `coll` satisfies an async test. If any
|
---|
3280 | * iteratee call returns `false`, the main `callback` is immediately called.
|
---|
3281 | *
|
---|
3282 | * @name every
|
---|
3283 | * @static
|
---|
3284 | * @memberOf module:Collections
|
---|
3285 | * @method
|
---|
3286 | * @alias all
|
---|
3287 | * @category Collection
|
---|
3288 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
3289 | * @param {AsyncFunction} iteratee - An async truth test to apply to each item
|
---|
3290 | * in the collection in parallel.
|
---|
3291 | * The iteratee must complete with a boolean result value.
|
---|
3292 | * Invoked with (item, callback).
|
---|
3293 | * @param {Function} [callback] - A callback which is called after all the
|
---|
3294 | * `iteratee` functions have finished. Result will be either `true` or `false`
|
---|
3295 | * depending on the values of the async tests. Invoked with (err, result).
|
---|
3296 | * @example
|
---|
3297 | *
|
---|
3298 | * async.every(['file1','file2','file3'], function(filePath, callback) {
|
---|
3299 | * fs.access(filePath, function(err) {
|
---|
3300 | * callback(null, !err)
|
---|
3301 | * });
|
---|
3302 | * }, function(err, result) {
|
---|
3303 | * // if result is true then every file exists
|
---|
3304 | * });
|
---|
3305 | */
|
---|
3306 | var every = doParallel(_createTester(notId, notId));
|
---|
3307 |
|
---|
3308 | /**
|
---|
3309 | * The same as [`every`]{@link module:Collections.every} but runs a maximum of `limit` async operations at a time.
|
---|
3310 | *
|
---|
3311 | * @name everyLimit
|
---|
3312 | * @static
|
---|
3313 | * @memberOf module:Collections
|
---|
3314 | * @method
|
---|
3315 | * @see [async.every]{@link module:Collections.every}
|
---|
3316 | * @alias allLimit
|
---|
3317 | * @category Collection
|
---|
3318 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
3319 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
3320 | * @param {AsyncFunction} iteratee - An async truth test to apply to each item
|
---|
3321 | * in the collection in parallel.
|
---|
3322 | * The iteratee must complete with a boolean result value.
|
---|
3323 | * Invoked with (item, callback).
|
---|
3324 | * @param {Function} [callback] - A callback which is called after all the
|
---|
3325 | * `iteratee` functions have finished. Result will be either `true` or `false`
|
---|
3326 | * depending on the values of the async tests. Invoked with (err, result).
|
---|
3327 | */
|
---|
3328 | var everyLimit = doParallelLimit(_createTester(notId, notId));
|
---|
3329 |
|
---|
3330 | /**
|
---|
3331 | * The same as [`every`]{@link module:Collections.every} but runs only a single async operation at a time.
|
---|
3332 | *
|
---|
3333 | * @name everySeries
|
---|
3334 | * @static
|
---|
3335 | * @memberOf module:Collections
|
---|
3336 | * @method
|
---|
3337 | * @see [async.every]{@link module:Collections.every}
|
---|
3338 | * @alias allSeries
|
---|
3339 | * @category Collection
|
---|
3340 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
3341 | * @param {AsyncFunction} iteratee - An async truth test to apply to each item
|
---|
3342 | * in the collection in series.
|
---|
3343 | * The iteratee must complete with a boolean result value.
|
---|
3344 | * Invoked with (item, callback).
|
---|
3345 | * @param {Function} [callback] - A callback which is called after all the
|
---|
3346 | * `iteratee` functions have finished. Result will be either `true` or `false`
|
---|
3347 | * depending on the values of the async tests. Invoked with (err, result).
|
---|
3348 | */
|
---|
3349 | var everySeries = doLimit(everyLimit, 1);
|
---|
3350 |
|
---|
3351 | /**
|
---|
3352 | * The base implementation of `_.property` without support for deep paths.
|
---|
3353 | *
|
---|
3354 | * @private
|
---|
3355 | * @param {string} key The key of the property to get.
|
---|
3356 | * @returns {Function} Returns the new accessor function.
|
---|
3357 | */
|
---|
3358 | function baseProperty(key) {
|
---|
3359 | return function(object) {
|
---|
3360 | return object == null ? undefined : object[key];
|
---|
3361 | };
|
---|
3362 | }
|
---|
3363 |
|
---|
3364 | function filterArray(eachfn, arr, iteratee, callback) {
|
---|
3365 | var truthValues = new Array(arr.length);
|
---|
3366 | eachfn(arr, function (x, index, callback) {
|
---|
3367 | iteratee(x, function (err, v) {
|
---|
3368 | truthValues[index] = !!v;
|
---|
3369 | callback(err);
|
---|
3370 | });
|
---|
3371 | }, function (err) {
|
---|
3372 | if (err) return callback(err);
|
---|
3373 | var results = [];
|
---|
3374 | for (var i = 0; i < arr.length; i++) {
|
---|
3375 | if (truthValues[i]) results.push(arr[i]);
|
---|
3376 | }
|
---|
3377 | callback(null, results);
|
---|
3378 | });
|
---|
3379 | }
|
---|
3380 |
|
---|
3381 | function filterGeneric(eachfn, coll, iteratee, callback) {
|
---|
3382 | var results = [];
|
---|
3383 | eachfn(coll, function (x, index, callback) {
|
---|
3384 | iteratee(x, function (err, v) {
|
---|
3385 | if (err) {
|
---|
3386 | callback(err);
|
---|
3387 | } else {
|
---|
3388 | if (v) {
|
---|
3389 | results.push({index: index, value: x});
|
---|
3390 | }
|
---|
3391 | callback();
|
---|
3392 | }
|
---|
3393 | });
|
---|
3394 | }, function (err) {
|
---|
3395 | if (err) {
|
---|
3396 | callback(err);
|
---|
3397 | } else {
|
---|
3398 | callback(null, arrayMap(results.sort(function (a, b) {
|
---|
3399 | return a.index - b.index;
|
---|
3400 | }), baseProperty('value')));
|
---|
3401 | }
|
---|
3402 | });
|
---|
3403 | }
|
---|
3404 |
|
---|
3405 | function _filter(eachfn, coll, iteratee, callback) {
|
---|
3406 | var filter = isArrayLike(coll) ? filterArray : filterGeneric;
|
---|
3407 | filter(eachfn, coll, wrapAsync(iteratee), callback || noop);
|
---|
3408 | }
|
---|
3409 |
|
---|
3410 | /**
|
---|
3411 | * Returns a new array of all the values in `coll` which pass an async truth
|
---|
3412 | * test. This operation is performed in parallel, but the results array will be
|
---|
3413 | * in the same order as the original.
|
---|
3414 | *
|
---|
3415 | * @name filter
|
---|
3416 | * @static
|
---|
3417 | * @memberOf module:Collections
|
---|
3418 | * @method
|
---|
3419 | * @alias select
|
---|
3420 | * @category Collection
|
---|
3421 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
3422 | * @param {Function} iteratee - A truth test to apply to each item in `coll`.
|
---|
3423 | * The `iteratee` is passed a `callback(err, truthValue)`, which must be called
|
---|
3424 | * with a boolean argument once it has completed. Invoked with (item, callback).
|
---|
3425 | * @param {Function} [callback] - A callback which is called after all the
|
---|
3426 | * `iteratee` functions have finished. Invoked with (err, results).
|
---|
3427 | * @example
|
---|
3428 | *
|
---|
3429 | * async.filter(['file1','file2','file3'], function(filePath, callback) {
|
---|
3430 | * fs.access(filePath, function(err) {
|
---|
3431 | * callback(null, !err)
|
---|
3432 | * });
|
---|
3433 | * }, function(err, results) {
|
---|
3434 | * // results now equals an array of the existing files
|
---|
3435 | * });
|
---|
3436 | */
|
---|
3437 | var filter = doParallel(_filter);
|
---|
3438 |
|
---|
3439 | /**
|
---|
3440 | * The same as [`filter`]{@link module:Collections.filter} but runs a maximum of `limit` async operations at a
|
---|
3441 | * time.
|
---|
3442 | *
|
---|
3443 | * @name filterLimit
|
---|
3444 | * @static
|
---|
3445 | * @memberOf module:Collections
|
---|
3446 | * @method
|
---|
3447 | * @see [async.filter]{@link module:Collections.filter}
|
---|
3448 | * @alias selectLimit
|
---|
3449 | * @category Collection
|
---|
3450 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
3451 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
3452 | * @param {Function} iteratee - A truth test to apply to each item in `coll`.
|
---|
3453 | * The `iteratee` is passed a `callback(err, truthValue)`, which must be called
|
---|
3454 | * with a boolean argument once it has completed. Invoked with (item, callback).
|
---|
3455 | * @param {Function} [callback] - A callback which is called after all the
|
---|
3456 | * `iteratee` functions have finished. Invoked with (err, results).
|
---|
3457 | */
|
---|
3458 | var filterLimit = doParallelLimit(_filter);
|
---|
3459 |
|
---|
3460 | /**
|
---|
3461 | * The same as [`filter`]{@link module:Collections.filter} but runs only a single async operation at a time.
|
---|
3462 | *
|
---|
3463 | * @name filterSeries
|
---|
3464 | * @static
|
---|
3465 | * @memberOf module:Collections
|
---|
3466 | * @method
|
---|
3467 | * @see [async.filter]{@link module:Collections.filter}
|
---|
3468 | * @alias selectSeries
|
---|
3469 | * @category Collection
|
---|
3470 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
3471 | * @param {Function} iteratee - A truth test to apply to each item in `coll`.
|
---|
3472 | * The `iteratee` is passed a `callback(err, truthValue)`, which must be called
|
---|
3473 | * with a boolean argument once it has completed. Invoked with (item, callback).
|
---|
3474 | * @param {Function} [callback] - A callback which is called after all the
|
---|
3475 | * `iteratee` functions have finished. Invoked with (err, results)
|
---|
3476 | */
|
---|
3477 | var filterSeries = doLimit(filterLimit, 1);
|
---|
3478 |
|
---|
3479 | /**
|
---|
3480 | * Calls the asynchronous function `fn` with a callback parameter that allows it
|
---|
3481 | * to call itself again, in series, indefinitely.
|
---|
3482 |
|
---|
3483 | * If an error is passed to the callback then `errback` is called with the
|
---|
3484 | * error, and execution stops, otherwise it will never be called.
|
---|
3485 | *
|
---|
3486 | * @name forever
|
---|
3487 | * @static
|
---|
3488 | * @memberOf module:ControlFlow
|
---|
3489 | * @method
|
---|
3490 | * @category Control Flow
|
---|
3491 | * @param {AsyncFunction} fn - an async function to call repeatedly.
|
---|
3492 | * Invoked with (next).
|
---|
3493 | * @param {Function} [errback] - when `fn` passes an error to it's callback,
|
---|
3494 | * this function will be called, and execution stops. Invoked with (err).
|
---|
3495 | * @example
|
---|
3496 | *
|
---|
3497 | * async.forever(
|
---|
3498 | * function(next) {
|
---|
3499 | * // next is suitable for passing to things that need a callback(err [, whatever]);
|
---|
3500 | * // it will result in this function being called again.
|
---|
3501 | * },
|
---|
3502 | * function(err) {
|
---|
3503 | * // if next is called with a value in its first parameter, it will appear
|
---|
3504 | * // in here as 'err', and execution will stop.
|
---|
3505 | * }
|
---|
3506 | * );
|
---|
3507 | */
|
---|
3508 | function forever(fn, errback) {
|
---|
3509 | var done = onlyOnce(errback || noop);
|
---|
3510 | var task = wrapAsync(ensureAsync(fn));
|
---|
3511 |
|
---|
3512 | function next(err) {
|
---|
3513 | if (err) return done(err);
|
---|
3514 | task(next);
|
---|
3515 | }
|
---|
3516 | next();
|
---|
3517 | }
|
---|
3518 |
|
---|
3519 | /**
|
---|
3520 | * The same as [`groupBy`]{@link module:Collections.groupBy} but runs a maximum of `limit` async operations at a time.
|
---|
3521 | *
|
---|
3522 | * @name groupByLimit
|
---|
3523 | * @static
|
---|
3524 | * @memberOf module:Collections
|
---|
3525 | * @method
|
---|
3526 | * @see [async.groupBy]{@link module:Collections.groupBy}
|
---|
3527 | * @category Collection
|
---|
3528 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
3529 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
3530 | * @param {AsyncFunction} iteratee - An async function to apply to each item in
|
---|
3531 | * `coll`.
|
---|
3532 | * The iteratee should complete with a `key` to group the value under.
|
---|
3533 | * Invoked with (value, callback).
|
---|
3534 | * @param {Function} [callback] - A callback which is called when all `iteratee`
|
---|
3535 | * functions have finished, or an error occurs. Result is an `Object` whoses
|
---|
3536 | * properties are arrays of values which returned the corresponding key.
|
---|
3537 | */
|
---|
3538 | var groupByLimit = function(coll, limit, iteratee, callback) {
|
---|
3539 | callback = callback || noop;
|
---|
3540 | var _iteratee = wrapAsync(iteratee);
|
---|
3541 | mapLimit(coll, limit, function(val, callback) {
|
---|
3542 | _iteratee(val, function(err, key) {
|
---|
3543 | if (err) return callback(err);
|
---|
3544 | return callback(null, {key: key, val: val});
|
---|
3545 | });
|
---|
3546 | }, function(err, mapResults) {
|
---|
3547 | var result = {};
|
---|
3548 | // from MDN, handle object having an `hasOwnProperty` prop
|
---|
3549 | var hasOwnProperty = Object.prototype.hasOwnProperty;
|
---|
3550 |
|
---|
3551 | for (var i = 0; i < mapResults.length; i++) {
|
---|
3552 | if (mapResults[i]) {
|
---|
3553 | var key = mapResults[i].key;
|
---|
3554 | var val = mapResults[i].val;
|
---|
3555 |
|
---|
3556 | if (hasOwnProperty.call(result, key)) {
|
---|
3557 | result[key].push(val);
|
---|
3558 | } else {
|
---|
3559 | result[key] = [val];
|
---|
3560 | }
|
---|
3561 | }
|
---|
3562 | }
|
---|
3563 |
|
---|
3564 | return callback(err, result);
|
---|
3565 | });
|
---|
3566 | };
|
---|
3567 |
|
---|
3568 | /**
|
---|
3569 | * Returns a new object, where each value corresponds to an array of items, from
|
---|
3570 | * `coll`, that returned the corresponding key. That is, the keys of the object
|
---|
3571 | * correspond to the values passed to the `iteratee` callback.
|
---|
3572 | *
|
---|
3573 | * Note: Since this function applies the `iteratee` to each item in parallel,
|
---|
3574 | * there is no guarantee that the `iteratee` functions will complete in order.
|
---|
3575 | * However, the values for each key in the `result` will be in the same order as
|
---|
3576 | * the original `coll`. For Objects, the values will roughly be in the order of
|
---|
3577 | * the original Objects' keys (but this can vary across JavaScript engines).
|
---|
3578 | *
|
---|
3579 | * @name groupBy
|
---|
3580 | * @static
|
---|
3581 | * @memberOf module:Collections
|
---|
3582 | * @method
|
---|
3583 | * @category Collection
|
---|
3584 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
3585 | * @param {AsyncFunction} iteratee - An async function to apply to each item in
|
---|
3586 | * `coll`.
|
---|
3587 | * The iteratee should complete with a `key` to group the value under.
|
---|
3588 | * Invoked with (value, callback).
|
---|
3589 | * @param {Function} [callback] - A callback which is called when all `iteratee`
|
---|
3590 | * functions have finished, or an error occurs. Result is an `Object` whoses
|
---|
3591 | * properties are arrays of values which returned the corresponding key.
|
---|
3592 | * @example
|
---|
3593 | *
|
---|
3594 | * async.groupBy(['userId1', 'userId2', 'userId3'], function(userId, callback) {
|
---|
3595 | * db.findById(userId, function(err, user) {
|
---|
3596 | * if (err) return callback(err);
|
---|
3597 | * return callback(null, user.age);
|
---|
3598 | * });
|
---|
3599 | * }, function(err, result) {
|
---|
3600 | * // result is object containing the userIds grouped by age
|
---|
3601 | * // e.g. { 30: ['userId1', 'userId3'], 42: ['userId2']};
|
---|
3602 | * });
|
---|
3603 | */
|
---|
3604 | var groupBy = doLimit(groupByLimit, Infinity);
|
---|
3605 |
|
---|
3606 | /**
|
---|
3607 | * The same as [`groupBy`]{@link module:Collections.groupBy} but runs only a single async operation at a time.
|
---|
3608 | *
|
---|
3609 | * @name groupBySeries
|
---|
3610 | * @static
|
---|
3611 | * @memberOf module:Collections
|
---|
3612 | * @method
|
---|
3613 | * @see [async.groupBy]{@link module:Collections.groupBy}
|
---|
3614 | * @category Collection
|
---|
3615 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
3616 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
3617 | * @param {AsyncFunction} iteratee - An async function to apply to each item in
|
---|
3618 | * `coll`.
|
---|
3619 | * The iteratee should complete with a `key` to group the value under.
|
---|
3620 | * Invoked with (value, callback).
|
---|
3621 | * @param {Function} [callback] - A callback which is called when all `iteratee`
|
---|
3622 | * functions have finished, or an error occurs. Result is an `Object` whoses
|
---|
3623 | * properties are arrays of values which returned the corresponding key.
|
---|
3624 | */
|
---|
3625 | var groupBySeries = doLimit(groupByLimit, 1);
|
---|
3626 |
|
---|
3627 | /**
|
---|
3628 | * Logs the result of an `async` function to the `console`. Only works in
|
---|
3629 | * Node.js or in browsers that support `console.log` and `console.error` (such
|
---|
3630 | * as FF and Chrome). If multiple arguments are returned from the async
|
---|
3631 | * function, `console.log` is called on each argument in order.
|
---|
3632 | *
|
---|
3633 | * @name log
|
---|
3634 | * @static
|
---|
3635 | * @memberOf module:Utils
|
---|
3636 | * @method
|
---|
3637 | * @category Util
|
---|
3638 | * @param {AsyncFunction} function - The function you want to eventually apply
|
---|
3639 | * all arguments to.
|
---|
3640 | * @param {...*} arguments... - Any number of arguments to apply to the function.
|
---|
3641 | * @example
|
---|
3642 | *
|
---|
3643 | * // in a module
|
---|
3644 | * var hello = function(name, callback) {
|
---|
3645 | * setTimeout(function() {
|
---|
3646 | * callback(null, 'hello ' + name);
|
---|
3647 | * }, 1000);
|
---|
3648 | * };
|
---|
3649 | *
|
---|
3650 | * // in the node repl
|
---|
3651 | * node> async.log(hello, 'world');
|
---|
3652 | * 'hello world'
|
---|
3653 | */
|
---|
3654 | var log = consoleFunc('log');
|
---|
3655 |
|
---|
3656 | /**
|
---|
3657 | * The same as [`mapValues`]{@link module:Collections.mapValues} but runs a maximum of `limit` async operations at a
|
---|
3658 | * time.
|
---|
3659 | *
|
---|
3660 | * @name mapValuesLimit
|
---|
3661 | * @static
|
---|
3662 | * @memberOf module:Collections
|
---|
3663 | * @method
|
---|
3664 | * @see [async.mapValues]{@link module:Collections.mapValues}
|
---|
3665 | * @category Collection
|
---|
3666 | * @param {Object} obj - A collection to iterate over.
|
---|
3667 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
3668 | * @param {AsyncFunction} iteratee - A function to apply to each value and key
|
---|
3669 | * in `coll`.
|
---|
3670 | * The iteratee should complete with the transformed value as its result.
|
---|
3671 | * Invoked with (value, key, callback).
|
---|
3672 | * @param {Function} [callback] - A callback which is called when all `iteratee`
|
---|
3673 | * functions have finished, or an error occurs. `result` is a new object consisting
|
---|
3674 | * of each key from `obj`, with each transformed value on the right-hand side.
|
---|
3675 | * Invoked with (err, result).
|
---|
3676 | */
|
---|
3677 | function mapValuesLimit(obj, limit, iteratee, callback) {
|
---|
3678 | callback = once(callback || noop);
|
---|
3679 | var newObj = {};
|
---|
3680 | var _iteratee = wrapAsync(iteratee);
|
---|
3681 | eachOfLimit(obj, limit, function(val, key, next) {
|
---|
3682 | _iteratee(val, key, function (err, result) {
|
---|
3683 | if (err) return next(err);
|
---|
3684 | newObj[key] = result;
|
---|
3685 | next();
|
---|
3686 | });
|
---|
3687 | }, function (err) {
|
---|
3688 | callback(err, newObj);
|
---|
3689 | });
|
---|
3690 | }
|
---|
3691 |
|
---|
3692 | /**
|
---|
3693 | * A relative of [`map`]{@link module:Collections.map}, designed for use with objects.
|
---|
3694 | *
|
---|
3695 | * Produces a new Object by mapping each value of `obj` through the `iteratee`
|
---|
3696 | * function. The `iteratee` is called each `value` and `key` from `obj` and a
|
---|
3697 | * callback for when it has finished processing. Each of these callbacks takes
|
---|
3698 | * two arguments: an `error`, and the transformed item from `obj`. If `iteratee`
|
---|
3699 | * passes an error to its callback, the main `callback` (for the `mapValues`
|
---|
3700 | * function) is immediately called with the error.
|
---|
3701 | *
|
---|
3702 | * Note, the order of the keys in the result is not guaranteed. The keys will
|
---|
3703 | * be roughly in the order they complete, (but this is very engine-specific)
|
---|
3704 | *
|
---|
3705 | * @name mapValues
|
---|
3706 | * @static
|
---|
3707 | * @memberOf module:Collections
|
---|
3708 | * @method
|
---|
3709 | * @category Collection
|
---|
3710 | * @param {Object} obj - A collection to iterate over.
|
---|
3711 | * @param {AsyncFunction} iteratee - A function to apply to each value and key
|
---|
3712 | * in `coll`.
|
---|
3713 | * The iteratee should complete with the transformed value as its result.
|
---|
3714 | * Invoked with (value, key, callback).
|
---|
3715 | * @param {Function} [callback] - A callback which is called when all `iteratee`
|
---|
3716 | * functions have finished, or an error occurs. `result` is a new object consisting
|
---|
3717 | * of each key from `obj`, with each transformed value on the right-hand side.
|
---|
3718 | * Invoked with (err, result).
|
---|
3719 | * @example
|
---|
3720 | *
|
---|
3721 | * async.mapValues({
|
---|
3722 | * f1: 'file1',
|
---|
3723 | * f2: 'file2',
|
---|
3724 | * f3: 'file3'
|
---|
3725 | * }, function (file, key, callback) {
|
---|
3726 | * fs.stat(file, callback);
|
---|
3727 | * }, function(err, result) {
|
---|
3728 | * // result is now a map of stats for each file, e.g.
|
---|
3729 | * // {
|
---|
3730 | * // f1: [stats for file1],
|
---|
3731 | * // f2: [stats for file2],
|
---|
3732 | * // f3: [stats for file3]
|
---|
3733 | * // }
|
---|
3734 | * });
|
---|
3735 | */
|
---|
3736 |
|
---|
3737 | var mapValues = doLimit(mapValuesLimit, Infinity);
|
---|
3738 |
|
---|
3739 | /**
|
---|
3740 | * The same as [`mapValues`]{@link module:Collections.mapValues} but runs only a single async operation at a time.
|
---|
3741 | *
|
---|
3742 | * @name mapValuesSeries
|
---|
3743 | * @static
|
---|
3744 | * @memberOf module:Collections
|
---|
3745 | * @method
|
---|
3746 | * @see [async.mapValues]{@link module:Collections.mapValues}
|
---|
3747 | * @category Collection
|
---|
3748 | * @param {Object} obj - A collection to iterate over.
|
---|
3749 | * @param {AsyncFunction} iteratee - A function to apply to each value and key
|
---|
3750 | * in `coll`.
|
---|
3751 | * The iteratee should complete with the transformed value as its result.
|
---|
3752 | * Invoked with (value, key, callback).
|
---|
3753 | * @param {Function} [callback] - A callback which is called when all `iteratee`
|
---|
3754 | * functions have finished, or an error occurs. `result` is a new object consisting
|
---|
3755 | * of each key from `obj`, with each transformed value on the right-hand side.
|
---|
3756 | * Invoked with (err, result).
|
---|
3757 | */
|
---|
3758 | var mapValuesSeries = doLimit(mapValuesLimit, 1);
|
---|
3759 |
|
---|
3760 | function has(obj, key) {
|
---|
3761 | return key in obj;
|
---|
3762 | }
|
---|
3763 |
|
---|
3764 | /**
|
---|
3765 | * Caches the results of an async function. When creating a hash to store
|
---|
3766 | * function results against, the callback is omitted from the hash and an
|
---|
3767 | * optional hash function can be used.
|
---|
3768 | *
|
---|
3769 | * If no hash function is specified, the first argument is used as a hash key,
|
---|
3770 | * which may work reasonably if it is a string or a data type that converts to a
|
---|
3771 | * distinct string. Note that objects and arrays will not behave reasonably.
|
---|
3772 | * Neither will cases where the other arguments are significant. In such cases,
|
---|
3773 | * specify your own hash function.
|
---|
3774 | *
|
---|
3775 | * The cache of results is exposed as the `memo` property of the function
|
---|
3776 | * returned by `memoize`.
|
---|
3777 | *
|
---|
3778 | * @name memoize
|
---|
3779 | * @static
|
---|
3780 | * @memberOf module:Utils
|
---|
3781 | * @method
|
---|
3782 | * @category Util
|
---|
3783 | * @param {AsyncFunction} fn - The async function to proxy and cache results from.
|
---|
3784 | * @param {Function} hasher - An optional function for generating a custom hash
|
---|
3785 | * for storing results. It has all the arguments applied to it apart from the
|
---|
3786 | * callback, and must be synchronous.
|
---|
3787 | * @returns {AsyncFunction} a memoized version of `fn`
|
---|
3788 | * @example
|
---|
3789 | *
|
---|
3790 | * var slow_fn = function(name, callback) {
|
---|
3791 | * // do something
|
---|
3792 | * callback(null, result);
|
---|
3793 | * };
|
---|
3794 | * var fn = async.memoize(slow_fn);
|
---|
3795 | *
|
---|
3796 | * // fn can now be used as if it were slow_fn
|
---|
3797 | * fn('some name', function() {
|
---|
3798 | * // callback
|
---|
3799 | * });
|
---|
3800 | */
|
---|
3801 | function memoize(fn, hasher) {
|
---|
3802 | var memo = Object.create(null);
|
---|
3803 | var queues = Object.create(null);
|
---|
3804 | hasher = hasher || identity;
|
---|
3805 | var _fn = wrapAsync(fn);
|
---|
3806 | var memoized = initialParams(function memoized(args, callback) {
|
---|
3807 | var key = hasher.apply(null, args);
|
---|
3808 | if (has(memo, key)) {
|
---|
3809 | setImmediate$1(function() {
|
---|
3810 | callback.apply(null, memo[key]);
|
---|
3811 | });
|
---|
3812 | } else if (has(queues, key)) {
|
---|
3813 | queues[key].push(callback);
|
---|
3814 | } else {
|
---|
3815 | queues[key] = [callback];
|
---|
3816 | _fn.apply(null, args.concat(function(/*args*/) {
|
---|
3817 | var args = slice(arguments);
|
---|
3818 | memo[key] = args;
|
---|
3819 | var q = queues[key];
|
---|
3820 | delete queues[key];
|
---|
3821 | for (var i = 0, l = q.length; i < l; i++) {
|
---|
3822 | q[i].apply(null, args);
|
---|
3823 | }
|
---|
3824 | }));
|
---|
3825 | }
|
---|
3826 | });
|
---|
3827 | memoized.memo = memo;
|
---|
3828 | memoized.unmemoized = fn;
|
---|
3829 | return memoized;
|
---|
3830 | }
|
---|
3831 |
|
---|
3832 | /**
|
---|
3833 | * Calls `callback` on a later loop around the event loop. In Node.js this just
|
---|
3834 | * calls `process.nextTick`. In the browser it will use `setImmediate` if
|
---|
3835 | * available, otherwise `setTimeout(callback, 0)`, which means other higher
|
---|
3836 | * priority events may precede the execution of `callback`.
|
---|
3837 | *
|
---|
3838 | * This is used internally for browser-compatibility purposes.
|
---|
3839 | *
|
---|
3840 | * @name nextTick
|
---|
3841 | * @static
|
---|
3842 | * @memberOf module:Utils
|
---|
3843 | * @method
|
---|
3844 | * @see [async.setImmediate]{@link module:Utils.setImmediate}
|
---|
3845 | * @category Util
|
---|
3846 | * @param {Function} callback - The function to call on a later loop around
|
---|
3847 | * the event loop. Invoked with (args...).
|
---|
3848 | * @param {...*} args... - any number of additional arguments to pass to the
|
---|
3849 | * callback on the next tick.
|
---|
3850 | * @example
|
---|
3851 | *
|
---|
3852 | * var call_order = [];
|
---|
3853 | * async.nextTick(function() {
|
---|
3854 | * call_order.push('two');
|
---|
3855 | * // call_order now equals ['one','two']
|
---|
3856 | * });
|
---|
3857 | * call_order.push('one');
|
---|
3858 | *
|
---|
3859 | * async.setImmediate(function (a, b, c) {
|
---|
3860 | * // a, b, and c equal 1, 2, and 3
|
---|
3861 | * }, 1, 2, 3);
|
---|
3862 | */
|
---|
3863 | var _defer$1;
|
---|
3864 |
|
---|
3865 | if (hasNextTick) {
|
---|
3866 | _defer$1 = process.nextTick;
|
---|
3867 | } else if (hasSetImmediate) {
|
---|
3868 | _defer$1 = setImmediate;
|
---|
3869 | } else {
|
---|
3870 | _defer$1 = fallback;
|
---|
3871 | }
|
---|
3872 |
|
---|
3873 | var nextTick = wrap(_defer$1);
|
---|
3874 |
|
---|
3875 | function _parallel(eachfn, tasks, callback) {
|
---|
3876 | callback = callback || noop;
|
---|
3877 | var results = isArrayLike(tasks) ? [] : {};
|
---|
3878 |
|
---|
3879 | eachfn(tasks, function (task, key, callback) {
|
---|
3880 | wrapAsync(task)(function (err, result) {
|
---|
3881 | if (arguments.length > 2) {
|
---|
3882 | result = slice(arguments, 1);
|
---|
3883 | }
|
---|
3884 | results[key] = result;
|
---|
3885 | callback(err);
|
---|
3886 | });
|
---|
3887 | }, function (err) {
|
---|
3888 | callback(err, results);
|
---|
3889 | });
|
---|
3890 | }
|
---|
3891 |
|
---|
3892 | /**
|
---|
3893 | * Run the `tasks` collection of functions in parallel, without waiting until
|
---|
3894 | * the previous function has completed. If any of the functions pass an error to
|
---|
3895 | * its callback, the main `callback` is immediately called with the value of the
|
---|
3896 | * error. Once the `tasks` have completed, the results are passed to the final
|
---|
3897 | * `callback` as an array.
|
---|
3898 | *
|
---|
3899 | * **Note:** `parallel` is about kicking-off I/O tasks in parallel, not about
|
---|
3900 | * parallel execution of code. If your tasks do not use any timers or perform
|
---|
3901 | * any I/O, they will actually be executed in series. Any synchronous setup
|
---|
3902 | * sections for each task will happen one after the other. JavaScript remains
|
---|
3903 | * single-threaded.
|
---|
3904 | *
|
---|
3905 | * **Hint:** Use [`reflect`]{@link module:Utils.reflect} to continue the
|
---|
3906 | * execution of other tasks when a task fails.
|
---|
3907 | *
|
---|
3908 | * It is also possible to use an object instead of an array. Each property will
|
---|
3909 | * be run as a function and the results will be passed to the final `callback`
|
---|
3910 | * as an object instead of an array. This can be a more readable way of handling
|
---|
3911 | * results from {@link async.parallel}.
|
---|
3912 | *
|
---|
3913 | * @name parallel
|
---|
3914 | * @static
|
---|
3915 | * @memberOf module:ControlFlow
|
---|
3916 | * @method
|
---|
3917 | * @category Control Flow
|
---|
3918 | * @param {Array|Iterable|Object} tasks - A collection of
|
---|
3919 | * [async functions]{@link AsyncFunction} to run.
|
---|
3920 | * Each async function can complete with any number of optional `result` values.
|
---|
3921 | * @param {Function} [callback] - An optional callback to run once all the
|
---|
3922 | * functions have completed successfully. This function gets a results array
|
---|
3923 | * (or object) containing all the result arguments passed to the task callbacks.
|
---|
3924 | * Invoked with (err, results).
|
---|
3925 | *
|
---|
3926 | * @example
|
---|
3927 | * async.parallel([
|
---|
3928 | * function(callback) {
|
---|
3929 | * setTimeout(function() {
|
---|
3930 | * callback(null, 'one');
|
---|
3931 | * }, 200);
|
---|
3932 | * },
|
---|
3933 | * function(callback) {
|
---|
3934 | * setTimeout(function() {
|
---|
3935 | * callback(null, 'two');
|
---|
3936 | * }, 100);
|
---|
3937 | * }
|
---|
3938 | * ],
|
---|
3939 | * // optional callback
|
---|
3940 | * function(err, results) {
|
---|
3941 | * // the results array will equal ['one','two'] even though
|
---|
3942 | * // the second function had a shorter timeout.
|
---|
3943 | * });
|
---|
3944 | *
|
---|
3945 | * // an example using an object instead of an array
|
---|
3946 | * async.parallel({
|
---|
3947 | * one: function(callback) {
|
---|
3948 | * setTimeout(function() {
|
---|
3949 | * callback(null, 1);
|
---|
3950 | * }, 200);
|
---|
3951 | * },
|
---|
3952 | * two: function(callback) {
|
---|
3953 | * setTimeout(function() {
|
---|
3954 | * callback(null, 2);
|
---|
3955 | * }, 100);
|
---|
3956 | * }
|
---|
3957 | * }, function(err, results) {
|
---|
3958 | * // results is now equals to: {one: 1, two: 2}
|
---|
3959 | * });
|
---|
3960 | */
|
---|
3961 | function parallelLimit(tasks, callback) {
|
---|
3962 | _parallel(eachOf, tasks, callback);
|
---|
3963 | }
|
---|
3964 |
|
---|
3965 | /**
|
---|
3966 | * The same as [`parallel`]{@link module:ControlFlow.parallel} but runs a maximum of `limit` async operations at a
|
---|
3967 | * time.
|
---|
3968 | *
|
---|
3969 | * @name parallelLimit
|
---|
3970 | * @static
|
---|
3971 | * @memberOf module:ControlFlow
|
---|
3972 | * @method
|
---|
3973 | * @see [async.parallel]{@link module:ControlFlow.parallel}
|
---|
3974 | * @category Control Flow
|
---|
3975 | * @param {Array|Iterable|Object} tasks - A collection of
|
---|
3976 | * [async functions]{@link AsyncFunction} to run.
|
---|
3977 | * Each async function can complete with any number of optional `result` values.
|
---|
3978 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
3979 | * @param {Function} [callback] - An optional callback to run once all the
|
---|
3980 | * functions have completed successfully. This function gets a results array
|
---|
3981 | * (or object) containing all the result arguments passed to the task callbacks.
|
---|
3982 | * Invoked with (err, results).
|
---|
3983 | */
|
---|
3984 | function parallelLimit$1(tasks, limit, callback) {
|
---|
3985 | _parallel(_eachOfLimit(limit), tasks, callback);
|
---|
3986 | }
|
---|
3987 |
|
---|
3988 | /**
|
---|
3989 | * A queue of tasks for the worker function to complete.
|
---|
3990 | * @typedef {Object} QueueObject
|
---|
3991 | * @memberOf module:ControlFlow
|
---|
3992 | * @property {Function} length - a function returning the number of items
|
---|
3993 | * waiting to be processed. Invoke with `queue.length()`.
|
---|
3994 | * @property {boolean} started - a boolean indicating whether or not any
|
---|
3995 | * items have been pushed and processed by the queue.
|
---|
3996 | * @property {Function} running - a function returning the number of items
|
---|
3997 | * currently being processed. Invoke with `queue.running()`.
|
---|
3998 | * @property {Function} workersList - a function returning the array of items
|
---|
3999 | * currently being processed. Invoke with `queue.workersList()`.
|
---|
4000 | * @property {Function} idle - a function returning false if there are items
|
---|
4001 | * waiting or being processed, or true if not. Invoke with `queue.idle()`.
|
---|
4002 | * @property {number} concurrency - an integer for determining how many `worker`
|
---|
4003 | * functions should be run in parallel. This property can be changed after a
|
---|
4004 | * `queue` is created to alter the concurrency on-the-fly.
|
---|
4005 | * @property {Function} push - add a new task to the `queue`. Calls `callback`
|
---|
4006 | * once the `worker` has finished processing the task. Instead of a single task,
|
---|
4007 | * a `tasks` array can be submitted. The respective callback is used for every
|
---|
4008 | * task in the list. Invoke with `queue.push(task, [callback])`,
|
---|
4009 | * @property {Function} unshift - add a new task to the front of the `queue`.
|
---|
4010 | * Invoke with `queue.unshift(task, [callback])`.
|
---|
4011 | * @property {Function} remove - remove items from the queue that match a test
|
---|
4012 | * function. The test function will be passed an object with a `data` property,
|
---|
4013 | * and a `priority` property, if this is a
|
---|
4014 | * [priorityQueue]{@link module:ControlFlow.priorityQueue} object.
|
---|
4015 | * Invoked with `queue.remove(testFn)`, where `testFn` is of the form
|
---|
4016 | * `function ({data, priority}) {}` and returns a Boolean.
|
---|
4017 | * @property {Function} saturated - a callback that is called when the number of
|
---|
4018 | * running workers hits the `concurrency` limit, and further tasks will be
|
---|
4019 | * queued.
|
---|
4020 | * @property {Function} unsaturated - a callback that is called when the number
|
---|
4021 | * of running workers is less than the `concurrency` & `buffer` limits, and
|
---|
4022 | * further tasks will not be queued.
|
---|
4023 | * @property {number} buffer - A minimum threshold buffer in order to say that
|
---|
4024 | * the `queue` is `unsaturated`.
|
---|
4025 | * @property {Function} empty - a callback that is called when the last item
|
---|
4026 | * from the `queue` is given to a `worker`.
|
---|
4027 | * @property {Function} drain - a callback that is called when the last item
|
---|
4028 | * from the `queue` has returned from the `worker`.
|
---|
4029 | * @property {Function} error - a callback that is called when a task errors.
|
---|
4030 | * Has the signature `function(error, task)`.
|
---|
4031 | * @property {boolean} paused - a boolean for determining whether the queue is
|
---|
4032 | * in a paused state.
|
---|
4033 | * @property {Function} pause - a function that pauses the processing of tasks
|
---|
4034 | * until `resume()` is called. Invoke with `queue.pause()`.
|
---|
4035 | * @property {Function} resume - a function that resumes the processing of
|
---|
4036 | * queued tasks when the queue is paused. Invoke with `queue.resume()`.
|
---|
4037 | * @property {Function} kill - a function that removes the `drain` callback and
|
---|
4038 | * empties remaining tasks from the queue forcing it to go idle. No more tasks
|
---|
4039 | * should be pushed to the queue after calling this function. Invoke with `queue.kill()`.
|
---|
4040 | */
|
---|
4041 |
|
---|
4042 | /**
|
---|
4043 | * Creates a `queue` object with the specified `concurrency`. Tasks added to the
|
---|
4044 | * `queue` are processed in parallel (up to the `concurrency` limit). If all
|
---|
4045 | * `worker`s are in progress, the task is queued until one becomes available.
|
---|
4046 | * Once a `worker` completes a `task`, that `task`'s callback is called.
|
---|
4047 | *
|
---|
4048 | * @name queue
|
---|
4049 | * @static
|
---|
4050 | * @memberOf module:ControlFlow
|
---|
4051 | * @method
|
---|
4052 | * @category Control Flow
|
---|
4053 | * @param {AsyncFunction} worker - An async function for processing a queued task.
|
---|
4054 | * If you want to handle errors from an individual task, pass a callback to
|
---|
4055 | * `q.push()`. Invoked with (task, callback).
|
---|
4056 | * @param {number} [concurrency=1] - An `integer` for determining how many
|
---|
4057 | * `worker` functions should be run in parallel. If omitted, the concurrency
|
---|
4058 | * defaults to `1`. If the concurrency is `0`, an error is thrown.
|
---|
4059 | * @returns {module:ControlFlow.QueueObject} A queue object to manage the tasks. Callbacks can
|
---|
4060 | * attached as certain properties to listen for specific events during the
|
---|
4061 | * lifecycle of the queue.
|
---|
4062 | * @example
|
---|
4063 | *
|
---|
4064 | * // create a queue object with concurrency 2
|
---|
4065 | * var q = async.queue(function(task, callback) {
|
---|
4066 | * console.log('hello ' + task.name);
|
---|
4067 | * callback();
|
---|
4068 | * }, 2);
|
---|
4069 | *
|
---|
4070 | * // assign a callback
|
---|
4071 | * q.drain = function() {
|
---|
4072 | * console.log('all items have been processed');
|
---|
4073 | * };
|
---|
4074 | *
|
---|
4075 | * // add some items to the queue
|
---|
4076 | * q.push({name: 'foo'}, function(err) {
|
---|
4077 | * console.log('finished processing foo');
|
---|
4078 | * });
|
---|
4079 | * q.push({name: 'bar'}, function (err) {
|
---|
4080 | * console.log('finished processing bar');
|
---|
4081 | * });
|
---|
4082 | *
|
---|
4083 | * // add some items to the queue (batch-wise)
|
---|
4084 | * q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function(err) {
|
---|
4085 | * console.log('finished processing item');
|
---|
4086 | * });
|
---|
4087 | *
|
---|
4088 | * // add some items to the front of the queue
|
---|
4089 | * q.unshift({name: 'bar'}, function (err) {
|
---|
4090 | * console.log('finished processing bar');
|
---|
4091 | * });
|
---|
4092 | */
|
---|
4093 | var queue$1 = function (worker, concurrency) {
|
---|
4094 | var _worker = wrapAsync(worker);
|
---|
4095 | return queue(function (items, cb) {
|
---|
4096 | _worker(items[0], cb);
|
---|
4097 | }, concurrency, 1);
|
---|
4098 | };
|
---|
4099 |
|
---|
4100 | /**
|
---|
4101 | * The same as [async.queue]{@link module:ControlFlow.queue} only tasks are assigned a priority and
|
---|
4102 | * completed in ascending priority order.
|
---|
4103 | *
|
---|
4104 | * @name priorityQueue
|
---|
4105 | * @static
|
---|
4106 | * @memberOf module:ControlFlow
|
---|
4107 | * @method
|
---|
4108 | * @see [async.queue]{@link module:ControlFlow.queue}
|
---|
4109 | * @category Control Flow
|
---|
4110 | * @param {AsyncFunction} worker - An async function for processing a queued task.
|
---|
4111 | * If you want to handle errors from an individual task, pass a callback to
|
---|
4112 | * `q.push()`.
|
---|
4113 | * Invoked with (task, callback).
|
---|
4114 | * @param {number} concurrency - An `integer` for determining how many `worker`
|
---|
4115 | * functions should be run in parallel. If omitted, the concurrency defaults to
|
---|
4116 | * `1`. If the concurrency is `0`, an error is thrown.
|
---|
4117 | * @returns {module:ControlFlow.QueueObject} A priorityQueue object to manage the tasks. There are two
|
---|
4118 | * differences between `queue` and `priorityQueue` objects:
|
---|
4119 | * * `push(task, priority, [callback])` - `priority` should be a number. If an
|
---|
4120 | * array of `tasks` is given, all tasks will be assigned the same priority.
|
---|
4121 | * * The `unshift` method was removed.
|
---|
4122 | */
|
---|
4123 | var priorityQueue = function(worker, concurrency) {
|
---|
4124 | // Start with a normal queue
|
---|
4125 | var q = queue$1(worker, concurrency);
|
---|
4126 |
|
---|
4127 | // Override push to accept second parameter representing priority
|
---|
4128 | q.push = function(data, priority, callback) {
|
---|
4129 | if (callback == null) callback = noop;
|
---|
4130 | if (typeof callback !== 'function') {
|
---|
4131 | throw new Error('task callback must be a function');
|
---|
4132 | }
|
---|
4133 | q.started = true;
|
---|
4134 | if (!isArray(data)) {
|
---|
4135 | data = [data];
|
---|
4136 | }
|
---|
4137 | if (data.length === 0) {
|
---|
4138 | // call drain immediately if there are no tasks
|
---|
4139 | return setImmediate$1(function() {
|
---|
4140 | q.drain();
|
---|
4141 | });
|
---|
4142 | }
|
---|
4143 |
|
---|
4144 | priority = priority || 0;
|
---|
4145 | var nextNode = q._tasks.head;
|
---|
4146 | while (nextNode && priority >= nextNode.priority) {
|
---|
4147 | nextNode = nextNode.next;
|
---|
4148 | }
|
---|
4149 |
|
---|
4150 | for (var i = 0, l = data.length; i < l; i++) {
|
---|
4151 | var item = {
|
---|
4152 | data: data[i],
|
---|
4153 | priority: priority,
|
---|
4154 | callback: callback
|
---|
4155 | };
|
---|
4156 |
|
---|
4157 | if (nextNode) {
|
---|
4158 | q._tasks.insertBefore(nextNode, item);
|
---|
4159 | } else {
|
---|
4160 | q._tasks.push(item);
|
---|
4161 | }
|
---|
4162 | }
|
---|
4163 | setImmediate$1(q.process);
|
---|
4164 | };
|
---|
4165 |
|
---|
4166 | // Remove unshift function
|
---|
4167 | delete q.unshift;
|
---|
4168 |
|
---|
4169 | return q;
|
---|
4170 | };
|
---|
4171 |
|
---|
4172 | /**
|
---|
4173 | * Runs the `tasks` array of functions in parallel, without waiting until the
|
---|
4174 | * previous function has completed. Once any of the `tasks` complete or pass an
|
---|
4175 | * error to its callback, the main `callback` is immediately called. It's
|
---|
4176 | * equivalent to `Promise.race()`.
|
---|
4177 | *
|
---|
4178 | * @name race
|
---|
4179 | * @static
|
---|
4180 | * @memberOf module:ControlFlow
|
---|
4181 | * @method
|
---|
4182 | * @category Control Flow
|
---|
4183 | * @param {Array} tasks - An array containing [async functions]{@link AsyncFunction}
|
---|
4184 | * to run. Each function can complete with an optional `result` value.
|
---|
4185 | * @param {Function} callback - A callback to run once any of the functions have
|
---|
4186 | * completed. This function gets an error or result from the first function that
|
---|
4187 | * completed. Invoked with (err, result).
|
---|
4188 | * @returns undefined
|
---|
4189 | * @example
|
---|
4190 | *
|
---|
4191 | * async.race([
|
---|
4192 | * function(callback) {
|
---|
4193 | * setTimeout(function() {
|
---|
4194 | * callback(null, 'one');
|
---|
4195 | * }, 200);
|
---|
4196 | * },
|
---|
4197 | * function(callback) {
|
---|
4198 | * setTimeout(function() {
|
---|
4199 | * callback(null, 'two');
|
---|
4200 | * }, 100);
|
---|
4201 | * }
|
---|
4202 | * ],
|
---|
4203 | * // main callback
|
---|
4204 | * function(err, result) {
|
---|
4205 | * // the result will be equal to 'two' as it finishes earlier
|
---|
4206 | * });
|
---|
4207 | */
|
---|
4208 | function race(tasks, callback) {
|
---|
4209 | callback = once(callback || noop);
|
---|
4210 | if (!isArray(tasks)) return callback(new TypeError('First argument to race must be an array of functions'));
|
---|
4211 | if (!tasks.length) return callback();
|
---|
4212 | for (var i = 0, l = tasks.length; i < l; i++) {
|
---|
4213 | wrapAsync(tasks[i])(callback);
|
---|
4214 | }
|
---|
4215 | }
|
---|
4216 |
|
---|
4217 | /**
|
---|
4218 | * Same as [`reduce`]{@link module:Collections.reduce}, only operates on `array` in reverse order.
|
---|
4219 | *
|
---|
4220 | * @name reduceRight
|
---|
4221 | * @static
|
---|
4222 | * @memberOf module:Collections
|
---|
4223 | * @method
|
---|
4224 | * @see [async.reduce]{@link module:Collections.reduce}
|
---|
4225 | * @alias foldr
|
---|
4226 | * @category Collection
|
---|
4227 | * @param {Array} array - A collection to iterate over.
|
---|
4228 | * @param {*} memo - The initial state of the reduction.
|
---|
4229 | * @param {AsyncFunction} iteratee - A function applied to each item in the
|
---|
4230 | * array to produce the next step in the reduction.
|
---|
4231 | * The `iteratee` should complete with the next state of the reduction.
|
---|
4232 | * If the iteratee complete with an error, the reduction is stopped and the
|
---|
4233 | * main `callback` is immediately called with the error.
|
---|
4234 | * Invoked with (memo, item, callback).
|
---|
4235 | * @param {Function} [callback] - A callback which is called after all the
|
---|
4236 | * `iteratee` functions have finished. Result is the reduced value. Invoked with
|
---|
4237 | * (err, result).
|
---|
4238 | */
|
---|
4239 | function reduceRight (array, memo, iteratee, callback) {
|
---|
4240 | var reversed = slice(array).reverse();
|
---|
4241 | reduce(reversed, memo, iteratee, callback);
|
---|
4242 | }
|
---|
4243 |
|
---|
4244 | /**
|
---|
4245 | * Wraps the async function in another function that always completes with a
|
---|
4246 | * result object, even when it errors.
|
---|
4247 | *
|
---|
4248 | * The result object has either the property `error` or `value`.
|
---|
4249 | *
|
---|
4250 | * @name reflect
|
---|
4251 | * @static
|
---|
4252 | * @memberOf module:Utils
|
---|
4253 | * @method
|
---|
4254 | * @category Util
|
---|
4255 | * @param {AsyncFunction} fn - The async function you want to wrap
|
---|
4256 | * @returns {Function} - A function that always passes null to it's callback as
|
---|
4257 | * the error. The second argument to the callback will be an `object` with
|
---|
4258 | * either an `error` or a `value` property.
|
---|
4259 | * @example
|
---|
4260 | *
|
---|
4261 | * async.parallel([
|
---|
4262 | * async.reflect(function(callback) {
|
---|
4263 | * // do some stuff ...
|
---|
4264 | * callback(null, 'one');
|
---|
4265 | * }),
|
---|
4266 | * async.reflect(function(callback) {
|
---|
4267 | * // do some more stuff but error ...
|
---|
4268 | * callback('bad stuff happened');
|
---|
4269 | * }),
|
---|
4270 | * async.reflect(function(callback) {
|
---|
4271 | * // do some more stuff ...
|
---|
4272 | * callback(null, 'two');
|
---|
4273 | * })
|
---|
4274 | * ],
|
---|
4275 | * // optional callback
|
---|
4276 | * function(err, results) {
|
---|
4277 | * // values
|
---|
4278 | * // results[0].value = 'one'
|
---|
4279 | * // results[1].error = 'bad stuff happened'
|
---|
4280 | * // results[2].value = 'two'
|
---|
4281 | * });
|
---|
4282 | */
|
---|
4283 | function reflect(fn) {
|
---|
4284 | var _fn = wrapAsync(fn);
|
---|
4285 | return initialParams(function reflectOn(args, reflectCallback) {
|
---|
4286 | args.push(function callback(error, cbArg) {
|
---|
4287 | if (error) {
|
---|
4288 | reflectCallback(null, { error: error });
|
---|
4289 | } else {
|
---|
4290 | var value;
|
---|
4291 | if (arguments.length <= 2) {
|
---|
4292 | value = cbArg;
|
---|
4293 | } else {
|
---|
4294 | value = slice(arguments, 1);
|
---|
4295 | }
|
---|
4296 | reflectCallback(null, { value: value });
|
---|
4297 | }
|
---|
4298 | });
|
---|
4299 |
|
---|
4300 | return _fn.apply(this, args);
|
---|
4301 | });
|
---|
4302 | }
|
---|
4303 |
|
---|
4304 | /**
|
---|
4305 | * A helper function that wraps an array or an object of functions with `reflect`.
|
---|
4306 | *
|
---|
4307 | * @name reflectAll
|
---|
4308 | * @static
|
---|
4309 | * @memberOf module:Utils
|
---|
4310 | * @method
|
---|
4311 | * @see [async.reflect]{@link module:Utils.reflect}
|
---|
4312 | * @category Util
|
---|
4313 | * @param {Array|Object|Iterable} tasks - The collection of
|
---|
4314 | * [async functions]{@link AsyncFunction} to wrap in `async.reflect`.
|
---|
4315 | * @returns {Array} Returns an array of async functions, each wrapped in
|
---|
4316 | * `async.reflect`
|
---|
4317 | * @example
|
---|
4318 | *
|
---|
4319 | * let tasks = [
|
---|
4320 | * function(callback) {
|
---|
4321 | * setTimeout(function() {
|
---|
4322 | * callback(null, 'one');
|
---|
4323 | * }, 200);
|
---|
4324 | * },
|
---|
4325 | * function(callback) {
|
---|
4326 | * // do some more stuff but error ...
|
---|
4327 | * callback(new Error('bad stuff happened'));
|
---|
4328 | * },
|
---|
4329 | * function(callback) {
|
---|
4330 | * setTimeout(function() {
|
---|
4331 | * callback(null, 'two');
|
---|
4332 | * }, 100);
|
---|
4333 | * }
|
---|
4334 | * ];
|
---|
4335 | *
|
---|
4336 | * async.parallel(async.reflectAll(tasks),
|
---|
4337 | * // optional callback
|
---|
4338 | * function(err, results) {
|
---|
4339 | * // values
|
---|
4340 | * // results[0].value = 'one'
|
---|
4341 | * // results[1].error = Error('bad stuff happened')
|
---|
4342 | * // results[2].value = 'two'
|
---|
4343 | * });
|
---|
4344 | *
|
---|
4345 | * // an example using an object instead of an array
|
---|
4346 | * let tasks = {
|
---|
4347 | * one: function(callback) {
|
---|
4348 | * setTimeout(function() {
|
---|
4349 | * callback(null, 'one');
|
---|
4350 | * }, 200);
|
---|
4351 | * },
|
---|
4352 | * two: function(callback) {
|
---|
4353 | * callback('two');
|
---|
4354 | * },
|
---|
4355 | * three: function(callback) {
|
---|
4356 | * setTimeout(function() {
|
---|
4357 | * callback(null, 'three');
|
---|
4358 | * }, 100);
|
---|
4359 | * }
|
---|
4360 | * };
|
---|
4361 | *
|
---|
4362 | * async.parallel(async.reflectAll(tasks),
|
---|
4363 | * // optional callback
|
---|
4364 | * function(err, results) {
|
---|
4365 | * // values
|
---|
4366 | * // results.one.value = 'one'
|
---|
4367 | * // results.two.error = 'two'
|
---|
4368 | * // results.three.value = 'three'
|
---|
4369 | * });
|
---|
4370 | */
|
---|
4371 | function reflectAll(tasks) {
|
---|
4372 | var results;
|
---|
4373 | if (isArray(tasks)) {
|
---|
4374 | results = arrayMap(tasks, reflect);
|
---|
4375 | } else {
|
---|
4376 | results = {};
|
---|
4377 | baseForOwn(tasks, function(task, key) {
|
---|
4378 | results[key] = reflect.call(this, task);
|
---|
4379 | });
|
---|
4380 | }
|
---|
4381 | return results;
|
---|
4382 | }
|
---|
4383 |
|
---|
4384 | function reject$1(eachfn, arr, iteratee, callback) {
|
---|
4385 | _filter(eachfn, arr, function(value, cb) {
|
---|
4386 | iteratee(value, function(err, v) {
|
---|
4387 | cb(err, !v);
|
---|
4388 | });
|
---|
4389 | }, callback);
|
---|
4390 | }
|
---|
4391 |
|
---|
4392 | /**
|
---|
4393 | * The opposite of [`filter`]{@link module:Collections.filter}. Removes values that pass an `async` truth test.
|
---|
4394 | *
|
---|
4395 | * @name reject
|
---|
4396 | * @static
|
---|
4397 | * @memberOf module:Collections
|
---|
4398 | * @method
|
---|
4399 | * @see [async.filter]{@link module:Collections.filter}
|
---|
4400 | * @category Collection
|
---|
4401 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
4402 | * @param {Function} iteratee - An async truth test to apply to each item in
|
---|
4403 | * `coll`.
|
---|
4404 | * The should complete with a boolean value as its `result`.
|
---|
4405 | * Invoked with (item, callback).
|
---|
4406 | * @param {Function} [callback] - A callback which is called after all the
|
---|
4407 | * `iteratee` functions have finished. Invoked with (err, results).
|
---|
4408 | * @example
|
---|
4409 | *
|
---|
4410 | * async.reject(['file1','file2','file3'], function(filePath, callback) {
|
---|
4411 | * fs.access(filePath, function(err) {
|
---|
4412 | * callback(null, !err)
|
---|
4413 | * });
|
---|
4414 | * }, function(err, results) {
|
---|
4415 | * // results now equals an array of missing files
|
---|
4416 | * createFiles(results);
|
---|
4417 | * });
|
---|
4418 | */
|
---|
4419 | var reject = doParallel(reject$1);
|
---|
4420 |
|
---|
4421 | /**
|
---|
4422 | * The same as [`reject`]{@link module:Collections.reject} but runs a maximum of `limit` async operations at a
|
---|
4423 | * time.
|
---|
4424 | *
|
---|
4425 | * @name rejectLimit
|
---|
4426 | * @static
|
---|
4427 | * @memberOf module:Collections
|
---|
4428 | * @method
|
---|
4429 | * @see [async.reject]{@link module:Collections.reject}
|
---|
4430 | * @category Collection
|
---|
4431 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
4432 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
4433 | * @param {Function} iteratee - An async truth test to apply to each item in
|
---|
4434 | * `coll`.
|
---|
4435 | * The should complete with a boolean value as its `result`.
|
---|
4436 | * Invoked with (item, callback).
|
---|
4437 | * @param {Function} [callback] - A callback which is called after all the
|
---|
4438 | * `iteratee` functions have finished. Invoked with (err, results).
|
---|
4439 | */
|
---|
4440 | var rejectLimit = doParallelLimit(reject$1);
|
---|
4441 |
|
---|
4442 | /**
|
---|
4443 | * The same as [`reject`]{@link module:Collections.reject} but runs only a single async operation at a time.
|
---|
4444 | *
|
---|
4445 | * @name rejectSeries
|
---|
4446 | * @static
|
---|
4447 | * @memberOf module:Collections
|
---|
4448 | * @method
|
---|
4449 | * @see [async.reject]{@link module:Collections.reject}
|
---|
4450 | * @category Collection
|
---|
4451 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
4452 | * @param {Function} iteratee - An async truth test to apply to each item in
|
---|
4453 | * `coll`.
|
---|
4454 | * The should complete with a boolean value as its `result`.
|
---|
4455 | * Invoked with (item, callback).
|
---|
4456 | * @param {Function} [callback] - A callback which is called after all the
|
---|
4457 | * `iteratee` functions have finished. Invoked with (err, results).
|
---|
4458 | */
|
---|
4459 | var rejectSeries = doLimit(rejectLimit, 1);
|
---|
4460 |
|
---|
4461 | /**
|
---|
4462 | * Creates a function that returns `value`.
|
---|
4463 | *
|
---|
4464 | * @static
|
---|
4465 | * @memberOf _
|
---|
4466 | * @since 2.4.0
|
---|
4467 | * @category Util
|
---|
4468 | * @param {*} value The value to return from the new function.
|
---|
4469 | * @returns {Function} Returns the new constant function.
|
---|
4470 | * @example
|
---|
4471 | *
|
---|
4472 | * var objects = _.times(2, _.constant({ 'a': 1 }));
|
---|
4473 | *
|
---|
4474 | * console.log(objects);
|
---|
4475 | * // => [{ 'a': 1 }, { 'a': 1 }]
|
---|
4476 | *
|
---|
4477 | * console.log(objects[0] === objects[1]);
|
---|
4478 | * // => true
|
---|
4479 | */
|
---|
4480 | function constant$1(value) {
|
---|
4481 | return function() {
|
---|
4482 | return value;
|
---|
4483 | };
|
---|
4484 | }
|
---|
4485 |
|
---|
4486 | /**
|
---|
4487 | * Attempts to get a successful response from `task` no more than `times` times
|
---|
4488 | * before returning an error. If the task is successful, the `callback` will be
|
---|
4489 | * passed the result of the successful task. If all attempts fail, the callback
|
---|
4490 | * will be passed the error and result (if any) of the final attempt.
|
---|
4491 | *
|
---|
4492 | * @name retry
|
---|
4493 | * @static
|
---|
4494 | * @memberOf module:ControlFlow
|
---|
4495 | * @method
|
---|
4496 | * @category Control Flow
|
---|
4497 | * @see [async.retryable]{@link module:ControlFlow.retryable}
|
---|
4498 | * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - Can be either an
|
---|
4499 | * object with `times` and `interval` or a number.
|
---|
4500 | * * `times` - The number of attempts to make before giving up. The default
|
---|
4501 | * is `5`.
|
---|
4502 | * * `interval` - The time to wait between retries, in milliseconds. The
|
---|
4503 | * default is `0`. The interval may also be specified as a function of the
|
---|
4504 | * retry count (see example).
|
---|
4505 | * * `errorFilter` - An optional synchronous function that is invoked on
|
---|
4506 | * erroneous result. If it returns `true` the retry attempts will continue;
|
---|
4507 | * if the function returns `false` the retry flow is aborted with the current
|
---|
4508 | * attempt's error and result being returned to the final callback.
|
---|
4509 | * Invoked with (err).
|
---|
4510 | * * If `opts` is a number, the number specifies the number of times to retry,
|
---|
4511 | * with the default interval of `0`.
|
---|
4512 | * @param {AsyncFunction} task - An async function to retry.
|
---|
4513 | * Invoked with (callback).
|
---|
4514 | * @param {Function} [callback] - An optional callback which is called when the
|
---|
4515 | * task has succeeded, or after the final failed attempt. It receives the `err`
|
---|
4516 | * and `result` arguments of the last attempt at completing the `task`. Invoked
|
---|
4517 | * with (err, results).
|
---|
4518 | *
|
---|
4519 | * @example
|
---|
4520 | *
|
---|
4521 | * // The `retry` function can be used as a stand-alone control flow by passing
|
---|
4522 | * // a callback, as shown below:
|
---|
4523 | *
|
---|
4524 | * // try calling apiMethod 3 times
|
---|
4525 | * async.retry(3, apiMethod, function(err, result) {
|
---|
4526 | * // do something with the result
|
---|
4527 | * });
|
---|
4528 | *
|
---|
4529 | * // try calling apiMethod 3 times, waiting 200 ms between each retry
|
---|
4530 | * async.retry({times: 3, interval: 200}, apiMethod, function(err, result) {
|
---|
4531 | * // do something with the result
|
---|
4532 | * });
|
---|
4533 | *
|
---|
4534 | * // try calling apiMethod 10 times with exponential backoff
|
---|
4535 | * // (i.e. intervals of 100, 200, 400, 800, 1600, ... milliseconds)
|
---|
4536 | * async.retry({
|
---|
4537 | * times: 10,
|
---|
4538 | * interval: function(retryCount) {
|
---|
4539 | * return 50 * Math.pow(2, retryCount);
|
---|
4540 | * }
|
---|
4541 | * }, apiMethod, function(err, result) {
|
---|
4542 | * // do something with the result
|
---|
4543 | * });
|
---|
4544 | *
|
---|
4545 | * // try calling apiMethod the default 5 times no delay between each retry
|
---|
4546 | * async.retry(apiMethod, function(err, result) {
|
---|
4547 | * // do something with the result
|
---|
4548 | * });
|
---|
4549 | *
|
---|
4550 | * // try calling apiMethod only when error condition satisfies, all other
|
---|
4551 | * // errors will abort the retry control flow and return to final callback
|
---|
4552 | * async.retry({
|
---|
4553 | * errorFilter: function(err) {
|
---|
4554 | * return err.message === 'Temporary error'; // only retry on a specific error
|
---|
4555 | * }
|
---|
4556 | * }, apiMethod, function(err, result) {
|
---|
4557 | * // do something with the result
|
---|
4558 | * });
|
---|
4559 | *
|
---|
4560 | * // to retry individual methods that are not as reliable within other
|
---|
4561 | * // control flow functions, use the `retryable` wrapper:
|
---|
4562 | * async.auto({
|
---|
4563 | * users: api.getUsers.bind(api),
|
---|
4564 | * payments: async.retryable(3, api.getPayments.bind(api))
|
---|
4565 | * }, function(err, results) {
|
---|
4566 | * // do something with the results
|
---|
4567 | * });
|
---|
4568 | *
|
---|
4569 | */
|
---|
4570 | function retry(opts, task, callback) {
|
---|
4571 | var DEFAULT_TIMES = 5;
|
---|
4572 | var DEFAULT_INTERVAL = 0;
|
---|
4573 |
|
---|
4574 | var options = {
|
---|
4575 | times: DEFAULT_TIMES,
|
---|
4576 | intervalFunc: constant$1(DEFAULT_INTERVAL)
|
---|
4577 | };
|
---|
4578 |
|
---|
4579 | function parseTimes(acc, t) {
|
---|
4580 | if (typeof t === 'object') {
|
---|
4581 | acc.times = +t.times || DEFAULT_TIMES;
|
---|
4582 |
|
---|
4583 | acc.intervalFunc = typeof t.interval === 'function' ?
|
---|
4584 | t.interval :
|
---|
4585 | constant$1(+t.interval || DEFAULT_INTERVAL);
|
---|
4586 |
|
---|
4587 | acc.errorFilter = t.errorFilter;
|
---|
4588 | } else if (typeof t === 'number' || typeof t === 'string') {
|
---|
4589 | acc.times = +t || DEFAULT_TIMES;
|
---|
4590 | } else {
|
---|
4591 | throw new Error("Invalid arguments for async.retry");
|
---|
4592 | }
|
---|
4593 | }
|
---|
4594 |
|
---|
4595 | if (arguments.length < 3 && typeof opts === 'function') {
|
---|
4596 | callback = task || noop;
|
---|
4597 | task = opts;
|
---|
4598 | } else {
|
---|
4599 | parseTimes(options, opts);
|
---|
4600 | callback = callback || noop;
|
---|
4601 | }
|
---|
4602 |
|
---|
4603 | if (typeof task !== 'function') {
|
---|
4604 | throw new Error("Invalid arguments for async.retry");
|
---|
4605 | }
|
---|
4606 |
|
---|
4607 | var _task = wrapAsync(task);
|
---|
4608 |
|
---|
4609 | var attempt = 1;
|
---|
4610 | function retryAttempt() {
|
---|
4611 | _task(function(err) {
|
---|
4612 | if (err && attempt++ < options.times &&
|
---|
4613 | (typeof options.errorFilter != 'function' ||
|
---|
4614 | options.errorFilter(err))) {
|
---|
4615 | setTimeout(retryAttempt, options.intervalFunc(attempt));
|
---|
4616 | } else {
|
---|
4617 | callback.apply(null, arguments);
|
---|
4618 | }
|
---|
4619 | });
|
---|
4620 | }
|
---|
4621 |
|
---|
4622 | retryAttempt();
|
---|
4623 | }
|
---|
4624 |
|
---|
4625 | /**
|
---|
4626 | * A close relative of [`retry`]{@link module:ControlFlow.retry}. This method
|
---|
4627 | * wraps a task and makes it retryable, rather than immediately calling it
|
---|
4628 | * with retries.
|
---|
4629 | *
|
---|
4630 | * @name retryable
|
---|
4631 | * @static
|
---|
4632 | * @memberOf module:ControlFlow
|
---|
4633 | * @method
|
---|
4634 | * @see [async.retry]{@link module:ControlFlow.retry}
|
---|
4635 | * @category Control Flow
|
---|
4636 | * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - optional
|
---|
4637 | * options, exactly the same as from `retry`
|
---|
4638 | * @param {AsyncFunction} task - the asynchronous function to wrap.
|
---|
4639 | * This function will be passed any arguments passed to the returned wrapper.
|
---|
4640 | * Invoked with (...args, callback).
|
---|
4641 | * @returns {AsyncFunction} The wrapped function, which when invoked, will
|
---|
4642 | * retry on an error, based on the parameters specified in `opts`.
|
---|
4643 | * This function will accept the same parameters as `task`.
|
---|
4644 | * @example
|
---|
4645 | *
|
---|
4646 | * async.auto({
|
---|
4647 | * dep1: async.retryable(3, getFromFlakyService),
|
---|
4648 | * process: ["dep1", async.retryable(3, function (results, cb) {
|
---|
4649 | * maybeProcessData(results.dep1, cb);
|
---|
4650 | * })]
|
---|
4651 | * }, callback);
|
---|
4652 | */
|
---|
4653 | var retryable = function (opts, task) {
|
---|
4654 | if (!task) {
|
---|
4655 | task = opts;
|
---|
4656 | opts = null;
|
---|
4657 | }
|
---|
4658 | var _task = wrapAsync(task);
|
---|
4659 | return initialParams(function (args, callback) {
|
---|
4660 | function taskFn(cb) {
|
---|
4661 | _task.apply(null, args.concat(cb));
|
---|
4662 | }
|
---|
4663 |
|
---|
4664 | if (opts) retry(opts, taskFn, callback);
|
---|
4665 | else retry(taskFn, callback);
|
---|
4666 |
|
---|
4667 | });
|
---|
4668 | };
|
---|
4669 |
|
---|
4670 | /**
|
---|
4671 | * Run the functions in the `tasks` collection in series, each one running once
|
---|
4672 | * the previous function has completed. If any functions in the series pass an
|
---|
4673 | * error to its callback, no more functions are run, and `callback` is
|
---|
4674 | * immediately called with the value of the error. Otherwise, `callback`
|
---|
4675 | * receives an array of results when `tasks` have completed.
|
---|
4676 | *
|
---|
4677 | * It is also possible to use an object instead of an array. Each property will
|
---|
4678 | * be run as a function, and the results will be passed to the final `callback`
|
---|
4679 | * as an object instead of an array. This can be a more readable way of handling
|
---|
4680 | * results from {@link async.series}.
|
---|
4681 | *
|
---|
4682 | * **Note** that while many implementations preserve the order of object
|
---|
4683 | * properties, the [ECMAScript Language Specification](http://www.ecma-international.org/ecma-262/5.1/#sec-8.6)
|
---|
4684 | * explicitly states that
|
---|
4685 | *
|
---|
4686 | * > The mechanics and order of enumerating the properties is not specified.
|
---|
4687 | *
|
---|
4688 | * So if you rely on the order in which your series of functions are executed,
|
---|
4689 | * and want this to work on all platforms, consider using an array.
|
---|
4690 | *
|
---|
4691 | * @name series
|
---|
4692 | * @static
|
---|
4693 | * @memberOf module:ControlFlow
|
---|
4694 | * @method
|
---|
4695 | * @category Control Flow
|
---|
4696 | * @param {Array|Iterable|Object} tasks - A collection containing
|
---|
4697 | * [async functions]{@link AsyncFunction} to run in series.
|
---|
4698 | * Each function can complete with any number of optional `result` values.
|
---|
4699 | * @param {Function} [callback] - An optional callback to run once all the
|
---|
4700 | * functions have completed. This function gets a results array (or object)
|
---|
4701 | * containing all the result arguments passed to the `task` callbacks. Invoked
|
---|
4702 | * with (err, result).
|
---|
4703 | * @example
|
---|
4704 | * async.series([
|
---|
4705 | * function(callback) {
|
---|
4706 | * // do some stuff ...
|
---|
4707 | * callback(null, 'one');
|
---|
4708 | * },
|
---|
4709 | * function(callback) {
|
---|
4710 | * // do some more stuff ...
|
---|
4711 | * callback(null, 'two');
|
---|
4712 | * }
|
---|
4713 | * ],
|
---|
4714 | * // optional callback
|
---|
4715 | * function(err, results) {
|
---|
4716 | * // results is now equal to ['one', 'two']
|
---|
4717 | * });
|
---|
4718 | *
|
---|
4719 | * async.series({
|
---|
4720 | * one: function(callback) {
|
---|
4721 | * setTimeout(function() {
|
---|
4722 | * callback(null, 1);
|
---|
4723 | * }, 200);
|
---|
4724 | * },
|
---|
4725 | * two: function(callback){
|
---|
4726 | * setTimeout(function() {
|
---|
4727 | * callback(null, 2);
|
---|
4728 | * }, 100);
|
---|
4729 | * }
|
---|
4730 | * }, function(err, results) {
|
---|
4731 | * // results is now equal to: {one: 1, two: 2}
|
---|
4732 | * });
|
---|
4733 | */
|
---|
4734 | function series(tasks, callback) {
|
---|
4735 | _parallel(eachOfSeries, tasks, callback);
|
---|
4736 | }
|
---|
4737 |
|
---|
4738 | /**
|
---|
4739 | * Returns `true` if at least one element in the `coll` satisfies an async test.
|
---|
4740 | * If any iteratee call returns `true`, the main `callback` is immediately
|
---|
4741 | * called.
|
---|
4742 | *
|
---|
4743 | * @name some
|
---|
4744 | * @static
|
---|
4745 | * @memberOf module:Collections
|
---|
4746 | * @method
|
---|
4747 | * @alias any
|
---|
4748 | * @category Collection
|
---|
4749 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
4750 | * @param {AsyncFunction} iteratee - An async truth test to apply to each item
|
---|
4751 | * in the collections in parallel.
|
---|
4752 | * The iteratee should complete with a boolean `result` value.
|
---|
4753 | * Invoked with (item, callback).
|
---|
4754 | * @param {Function} [callback] - A callback which is called as soon as any
|
---|
4755 | * iteratee returns `true`, or after all the iteratee functions have finished.
|
---|
4756 | * Result will be either `true` or `false` depending on the values of the async
|
---|
4757 | * tests. Invoked with (err, result).
|
---|
4758 | * @example
|
---|
4759 | *
|
---|
4760 | * async.some(['file1','file2','file3'], function(filePath, callback) {
|
---|
4761 | * fs.access(filePath, function(err) {
|
---|
4762 | * callback(null, !err)
|
---|
4763 | * });
|
---|
4764 | * }, function(err, result) {
|
---|
4765 | * // if result is true then at least one of the files exists
|
---|
4766 | * });
|
---|
4767 | */
|
---|
4768 | var some = doParallel(_createTester(Boolean, identity));
|
---|
4769 |
|
---|
4770 | /**
|
---|
4771 | * The same as [`some`]{@link module:Collections.some} but runs a maximum of `limit` async operations at a time.
|
---|
4772 | *
|
---|
4773 | * @name someLimit
|
---|
4774 | * @static
|
---|
4775 | * @memberOf module:Collections
|
---|
4776 | * @method
|
---|
4777 | * @see [async.some]{@link module:Collections.some}
|
---|
4778 | * @alias anyLimit
|
---|
4779 | * @category Collection
|
---|
4780 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
4781 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
4782 | * @param {AsyncFunction} iteratee - An async truth test to apply to each item
|
---|
4783 | * in the collections in parallel.
|
---|
4784 | * The iteratee should complete with a boolean `result` value.
|
---|
4785 | * Invoked with (item, callback).
|
---|
4786 | * @param {Function} [callback] - A callback which is called as soon as any
|
---|
4787 | * iteratee returns `true`, or after all the iteratee functions have finished.
|
---|
4788 | * Result will be either `true` or `false` depending on the values of the async
|
---|
4789 | * tests. Invoked with (err, result).
|
---|
4790 | */
|
---|
4791 | var someLimit = doParallelLimit(_createTester(Boolean, identity));
|
---|
4792 |
|
---|
4793 | /**
|
---|
4794 | * The same as [`some`]{@link module:Collections.some} but runs only a single async operation at a time.
|
---|
4795 | *
|
---|
4796 | * @name someSeries
|
---|
4797 | * @static
|
---|
4798 | * @memberOf module:Collections
|
---|
4799 | * @method
|
---|
4800 | * @see [async.some]{@link module:Collections.some}
|
---|
4801 | * @alias anySeries
|
---|
4802 | * @category Collection
|
---|
4803 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
4804 | * @param {AsyncFunction} iteratee - An async truth test to apply to each item
|
---|
4805 | * in the collections in series.
|
---|
4806 | * The iteratee should complete with a boolean `result` value.
|
---|
4807 | * Invoked with (item, callback).
|
---|
4808 | * @param {Function} [callback] - A callback which is called as soon as any
|
---|
4809 | * iteratee returns `true`, or after all the iteratee functions have finished.
|
---|
4810 | * Result will be either `true` or `false` depending on the values of the async
|
---|
4811 | * tests. Invoked with (err, result).
|
---|
4812 | */
|
---|
4813 | var someSeries = doLimit(someLimit, 1);
|
---|
4814 |
|
---|
4815 | /**
|
---|
4816 | * Sorts a list by the results of running each `coll` value through an async
|
---|
4817 | * `iteratee`.
|
---|
4818 | *
|
---|
4819 | * @name sortBy
|
---|
4820 | * @static
|
---|
4821 | * @memberOf module:Collections
|
---|
4822 | * @method
|
---|
4823 | * @category Collection
|
---|
4824 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
4825 | * @param {AsyncFunction} iteratee - An async function to apply to each item in
|
---|
4826 | * `coll`.
|
---|
4827 | * The iteratee should complete with a value to use as the sort criteria as
|
---|
4828 | * its `result`.
|
---|
4829 | * Invoked with (item, callback).
|
---|
4830 | * @param {Function} callback - A callback which is called after all the
|
---|
4831 | * `iteratee` functions have finished, or an error occurs. Results is the items
|
---|
4832 | * from the original `coll` sorted by the values returned by the `iteratee`
|
---|
4833 | * calls. Invoked with (err, results).
|
---|
4834 | * @example
|
---|
4835 | *
|
---|
4836 | * async.sortBy(['file1','file2','file3'], function(file, callback) {
|
---|
4837 | * fs.stat(file, function(err, stats) {
|
---|
4838 | * callback(err, stats.mtime);
|
---|
4839 | * });
|
---|
4840 | * }, function(err, results) {
|
---|
4841 | * // results is now the original array of files sorted by
|
---|
4842 | * // modified date
|
---|
4843 | * });
|
---|
4844 | *
|
---|
4845 | * // By modifying the callback parameter the
|
---|
4846 | * // sorting order can be influenced:
|
---|
4847 | *
|
---|
4848 | * // ascending order
|
---|
4849 | * async.sortBy([1,9,3,5], function(x, callback) {
|
---|
4850 | * callback(null, x);
|
---|
4851 | * }, function(err,result) {
|
---|
4852 | * // result callback
|
---|
4853 | * });
|
---|
4854 | *
|
---|
4855 | * // descending order
|
---|
4856 | * async.sortBy([1,9,3,5], function(x, callback) {
|
---|
4857 | * callback(null, x*-1); //<- x*-1 instead of x, turns the order around
|
---|
4858 | * }, function(err,result) {
|
---|
4859 | * // result callback
|
---|
4860 | * });
|
---|
4861 | */
|
---|
4862 | function sortBy (coll, iteratee, callback) {
|
---|
4863 | var _iteratee = wrapAsync(iteratee);
|
---|
4864 | map(coll, function (x, callback) {
|
---|
4865 | _iteratee(x, function (err, criteria) {
|
---|
4866 | if (err) return callback(err);
|
---|
4867 | callback(null, {value: x, criteria: criteria});
|
---|
4868 | });
|
---|
4869 | }, function (err, results) {
|
---|
4870 | if (err) return callback(err);
|
---|
4871 | callback(null, arrayMap(results.sort(comparator), baseProperty('value')));
|
---|
4872 | });
|
---|
4873 |
|
---|
4874 | function comparator(left, right) {
|
---|
4875 | var a = left.criteria, b = right.criteria;
|
---|
4876 | return a < b ? -1 : a > b ? 1 : 0;
|
---|
4877 | }
|
---|
4878 | }
|
---|
4879 |
|
---|
4880 | /**
|
---|
4881 | * Sets a time limit on an asynchronous function. If the function does not call
|
---|
4882 | * its callback within the specified milliseconds, it will be called with a
|
---|
4883 | * timeout error. The code property for the error object will be `'ETIMEDOUT'`.
|
---|
4884 | *
|
---|
4885 | * @name timeout
|
---|
4886 | * @static
|
---|
4887 | * @memberOf module:Utils
|
---|
4888 | * @method
|
---|
4889 | * @category Util
|
---|
4890 | * @param {AsyncFunction} asyncFn - The async function to limit in time.
|
---|
4891 | * @param {number} milliseconds - The specified time limit.
|
---|
4892 | * @param {*} [info] - Any variable you want attached (`string`, `object`, etc)
|
---|
4893 | * to timeout Error for more information..
|
---|
4894 | * @returns {AsyncFunction} Returns a wrapped function that can be used with any
|
---|
4895 | * of the control flow functions.
|
---|
4896 | * Invoke this function with the same parameters as you would `asyncFunc`.
|
---|
4897 | * @example
|
---|
4898 | *
|
---|
4899 | * function myFunction(foo, callback) {
|
---|
4900 | * doAsyncTask(foo, function(err, data) {
|
---|
4901 | * // handle errors
|
---|
4902 | * if (err) return callback(err);
|
---|
4903 | *
|
---|
4904 | * // do some stuff ...
|
---|
4905 | *
|
---|
4906 | * // return processed data
|
---|
4907 | * return callback(null, data);
|
---|
4908 | * });
|
---|
4909 | * }
|
---|
4910 | *
|
---|
4911 | * var wrapped = async.timeout(myFunction, 1000);
|
---|
4912 | *
|
---|
4913 | * // call `wrapped` as you would `myFunction`
|
---|
4914 | * wrapped({ bar: 'bar' }, function(err, data) {
|
---|
4915 | * // if `myFunction` takes < 1000 ms to execute, `err`
|
---|
4916 | * // and `data` will have their expected values
|
---|
4917 | *
|
---|
4918 | * // else `err` will be an Error with the code 'ETIMEDOUT'
|
---|
4919 | * });
|
---|
4920 | */
|
---|
4921 | function timeout(asyncFn, milliseconds, info) {
|
---|
4922 | var fn = wrapAsync(asyncFn);
|
---|
4923 |
|
---|
4924 | return initialParams(function (args, callback) {
|
---|
4925 | var timedOut = false;
|
---|
4926 | var timer;
|
---|
4927 |
|
---|
4928 | function timeoutCallback() {
|
---|
4929 | var name = asyncFn.name || 'anonymous';
|
---|
4930 | var error = new Error('Callback function "' + name + '" timed out.');
|
---|
4931 | error.code = 'ETIMEDOUT';
|
---|
4932 | if (info) {
|
---|
4933 | error.info = info;
|
---|
4934 | }
|
---|
4935 | timedOut = true;
|
---|
4936 | callback(error);
|
---|
4937 | }
|
---|
4938 |
|
---|
4939 | args.push(function () {
|
---|
4940 | if (!timedOut) {
|
---|
4941 | callback.apply(null, arguments);
|
---|
4942 | clearTimeout(timer);
|
---|
4943 | }
|
---|
4944 | });
|
---|
4945 |
|
---|
4946 | // setup timer and call original function
|
---|
4947 | timer = setTimeout(timeoutCallback, milliseconds);
|
---|
4948 | fn.apply(null, args);
|
---|
4949 | });
|
---|
4950 | }
|
---|
4951 |
|
---|
4952 | /* Built-in method references for those with the same name as other `lodash` methods. */
|
---|
4953 | var nativeCeil = Math.ceil;
|
---|
4954 | var nativeMax = Math.max;
|
---|
4955 |
|
---|
4956 | /**
|
---|
4957 | * The base implementation of `_.range` and `_.rangeRight` which doesn't
|
---|
4958 | * coerce arguments.
|
---|
4959 | *
|
---|
4960 | * @private
|
---|
4961 | * @param {number} start The start of the range.
|
---|
4962 | * @param {number} end The end of the range.
|
---|
4963 | * @param {number} step The value to increment or decrement by.
|
---|
4964 | * @param {boolean} [fromRight] Specify iterating from right to left.
|
---|
4965 | * @returns {Array} Returns the range of numbers.
|
---|
4966 | */
|
---|
4967 | function baseRange(start, end, step, fromRight) {
|
---|
4968 | var index = -1,
|
---|
4969 | length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
|
---|
4970 | result = Array(length);
|
---|
4971 |
|
---|
4972 | while (length--) {
|
---|
4973 | result[fromRight ? length : ++index] = start;
|
---|
4974 | start += step;
|
---|
4975 | }
|
---|
4976 | return result;
|
---|
4977 | }
|
---|
4978 |
|
---|
4979 | /**
|
---|
4980 | * The same as [times]{@link module:ControlFlow.times} but runs a maximum of `limit` async operations at a
|
---|
4981 | * time.
|
---|
4982 | *
|
---|
4983 | * @name timesLimit
|
---|
4984 | * @static
|
---|
4985 | * @memberOf module:ControlFlow
|
---|
4986 | * @method
|
---|
4987 | * @see [async.times]{@link module:ControlFlow.times}
|
---|
4988 | * @category Control Flow
|
---|
4989 | * @param {number} count - The number of times to run the function.
|
---|
4990 | * @param {number} limit - The maximum number of async operations at a time.
|
---|
4991 | * @param {AsyncFunction} iteratee - The async function to call `n` times.
|
---|
4992 | * Invoked with the iteration index and a callback: (n, next).
|
---|
4993 | * @param {Function} callback - see [async.map]{@link module:Collections.map}.
|
---|
4994 | */
|
---|
4995 | function timeLimit(count, limit, iteratee, callback) {
|
---|
4996 | var _iteratee = wrapAsync(iteratee);
|
---|
4997 | mapLimit(baseRange(0, count, 1), limit, _iteratee, callback);
|
---|
4998 | }
|
---|
4999 |
|
---|
5000 | /**
|
---|
5001 | * Calls the `iteratee` function `n` times, and accumulates results in the same
|
---|
5002 | * manner you would use with [map]{@link module:Collections.map}.
|
---|
5003 | *
|
---|
5004 | * @name times
|
---|
5005 | * @static
|
---|
5006 | * @memberOf module:ControlFlow
|
---|
5007 | * @method
|
---|
5008 | * @see [async.map]{@link module:Collections.map}
|
---|
5009 | * @category Control Flow
|
---|
5010 | * @param {number} n - The number of times to run the function.
|
---|
5011 | * @param {AsyncFunction} iteratee - The async function to call `n` times.
|
---|
5012 | * Invoked with the iteration index and a callback: (n, next).
|
---|
5013 | * @param {Function} callback - see {@link module:Collections.map}.
|
---|
5014 | * @example
|
---|
5015 | *
|
---|
5016 | * // Pretend this is some complicated async factory
|
---|
5017 | * var createUser = function(id, callback) {
|
---|
5018 | * callback(null, {
|
---|
5019 | * id: 'user' + id
|
---|
5020 | * });
|
---|
5021 | * };
|
---|
5022 | *
|
---|
5023 | * // generate 5 users
|
---|
5024 | * async.times(5, function(n, next) {
|
---|
5025 | * createUser(n, function(err, user) {
|
---|
5026 | * next(err, user);
|
---|
5027 | * });
|
---|
5028 | * }, function(err, users) {
|
---|
5029 | * // we should now have 5 users
|
---|
5030 | * });
|
---|
5031 | */
|
---|
5032 | var times = doLimit(timeLimit, Infinity);
|
---|
5033 |
|
---|
5034 | /**
|
---|
5035 | * The same as [times]{@link module:ControlFlow.times} but runs only a single async operation at a time.
|
---|
5036 | *
|
---|
5037 | * @name timesSeries
|
---|
5038 | * @static
|
---|
5039 | * @memberOf module:ControlFlow
|
---|
5040 | * @method
|
---|
5041 | * @see [async.times]{@link module:ControlFlow.times}
|
---|
5042 | * @category Control Flow
|
---|
5043 | * @param {number} n - The number of times to run the function.
|
---|
5044 | * @param {AsyncFunction} iteratee - The async function to call `n` times.
|
---|
5045 | * Invoked with the iteration index and a callback: (n, next).
|
---|
5046 | * @param {Function} callback - see {@link module:Collections.map}.
|
---|
5047 | */
|
---|
5048 | var timesSeries = doLimit(timeLimit, 1);
|
---|
5049 |
|
---|
5050 | /**
|
---|
5051 | * A relative of `reduce`. Takes an Object or Array, and iterates over each
|
---|
5052 | * element in series, each step potentially mutating an `accumulator` value.
|
---|
5053 | * The type of the accumulator defaults to the type of collection passed in.
|
---|
5054 | *
|
---|
5055 | * @name transform
|
---|
5056 | * @static
|
---|
5057 | * @memberOf module:Collections
|
---|
5058 | * @method
|
---|
5059 | * @category Collection
|
---|
5060 | * @param {Array|Iterable|Object} coll - A collection to iterate over.
|
---|
5061 | * @param {*} [accumulator] - The initial state of the transform. If omitted,
|
---|
5062 | * it will default to an empty Object or Array, depending on the type of `coll`
|
---|
5063 | * @param {AsyncFunction} iteratee - A function applied to each item in the
|
---|
5064 | * collection that potentially modifies the accumulator.
|
---|
5065 | * Invoked with (accumulator, item, key, callback).
|
---|
5066 | * @param {Function} [callback] - A callback which is called after all the
|
---|
5067 | * `iteratee` functions have finished. Result is the transformed accumulator.
|
---|
5068 | * Invoked with (err, result).
|
---|
5069 | * @example
|
---|
5070 | *
|
---|
5071 | * async.transform([1,2,3], function(acc, item, index, callback) {
|
---|
5072 | * // pointless async:
|
---|
5073 | * process.nextTick(function() {
|
---|
5074 | * acc.push(item * 2)
|
---|
5075 | * callback(null)
|
---|
5076 | * });
|
---|
5077 | * }, function(err, result) {
|
---|
5078 | * // result is now equal to [2, 4, 6]
|
---|
5079 | * });
|
---|
5080 | *
|
---|
5081 | * @example
|
---|
5082 | *
|
---|
5083 | * async.transform({a: 1, b: 2, c: 3}, function (obj, val, key, callback) {
|
---|
5084 | * setImmediate(function () {
|
---|
5085 | * obj[key] = val * 2;
|
---|
5086 | * callback();
|
---|
5087 | * })
|
---|
5088 | * }, function (err, result) {
|
---|
5089 | * // result is equal to {a: 2, b: 4, c: 6}
|
---|
5090 | * })
|
---|
5091 | */
|
---|
5092 | function transform (coll, accumulator, iteratee, callback) {
|
---|
5093 | if (arguments.length <= 3) {
|
---|
5094 | callback = iteratee;
|
---|
5095 | iteratee = accumulator;
|
---|
5096 | accumulator = isArray(coll) ? [] : {};
|
---|
5097 | }
|
---|
5098 | callback = once(callback || noop);
|
---|
5099 | var _iteratee = wrapAsync(iteratee);
|
---|
5100 |
|
---|
5101 | eachOf(coll, function(v, k, cb) {
|
---|
5102 | _iteratee(accumulator, v, k, cb);
|
---|
5103 | }, function(err) {
|
---|
5104 | callback(err, accumulator);
|
---|
5105 | });
|
---|
5106 | }
|
---|
5107 |
|
---|
5108 | /**
|
---|
5109 | * It runs each task in series but stops whenever any of the functions were
|
---|
5110 | * successful. If one of the tasks were successful, the `callback` will be
|
---|
5111 | * passed the result of the successful task. If all tasks fail, the callback
|
---|
5112 | * will be passed the error and result (if any) of the final attempt.
|
---|
5113 | *
|
---|
5114 | * @name tryEach
|
---|
5115 | * @static
|
---|
5116 | * @memberOf module:ControlFlow
|
---|
5117 | * @method
|
---|
5118 | * @category Control Flow
|
---|
5119 | * @param {Array|Iterable|Object} tasks - A collection containing functions to
|
---|
5120 | * run, each function is passed a `callback(err, result)` it must call on
|
---|
5121 | * completion with an error `err` (which can be `null`) and an optional `result`
|
---|
5122 | * value.
|
---|
5123 | * @param {Function} [callback] - An optional callback which is called when one
|
---|
5124 | * of the tasks has succeeded, or all have failed. It receives the `err` and
|
---|
5125 | * `result` arguments of the last attempt at completing the `task`. Invoked with
|
---|
5126 | * (err, results).
|
---|
5127 | * @example
|
---|
5128 | * async.tryEach([
|
---|
5129 | * function getDataFromFirstWebsite(callback) {
|
---|
5130 | * // Try getting the data from the first website
|
---|
5131 | * callback(err, data);
|
---|
5132 | * },
|
---|
5133 | * function getDataFromSecondWebsite(callback) {
|
---|
5134 | * // First website failed,
|
---|
5135 | * // Try getting the data from the backup website
|
---|
5136 | * callback(err, data);
|
---|
5137 | * }
|
---|
5138 | * ],
|
---|
5139 | * // optional callback
|
---|
5140 | * function(err, results) {
|
---|
5141 | * Now do something with the data.
|
---|
5142 | * });
|
---|
5143 | *
|
---|
5144 | */
|
---|
5145 | function tryEach(tasks, callback) {
|
---|
5146 | var error = null;
|
---|
5147 | var result;
|
---|
5148 | callback = callback || noop;
|
---|
5149 | eachSeries(tasks, function(task, callback) {
|
---|
5150 | wrapAsync(task)(function (err, res/*, ...args*/) {
|
---|
5151 | if (arguments.length > 2) {
|
---|
5152 | result = slice(arguments, 1);
|
---|
5153 | } else {
|
---|
5154 | result = res;
|
---|
5155 | }
|
---|
5156 | error = err;
|
---|
5157 | callback(!err);
|
---|
5158 | });
|
---|
5159 | }, function () {
|
---|
5160 | callback(error, result);
|
---|
5161 | });
|
---|
5162 | }
|
---|
5163 |
|
---|
5164 | /**
|
---|
5165 | * Undoes a [memoize]{@link module:Utils.memoize}d function, reverting it to the original,
|
---|
5166 | * unmemoized form. Handy for testing.
|
---|
5167 | *
|
---|
5168 | * @name unmemoize
|
---|
5169 | * @static
|
---|
5170 | * @memberOf module:Utils
|
---|
5171 | * @method
|
---|
5172 | * @see [async.memoize]{@link module:Utils.memoize}
|
---|
5173 | * @category Util
|
---|
5174 | * @param {AsyncFunction} fn - the memoized function
|
---|
5175 | * @returns {AsyncFunction} a function that calls the original unmemoized function
|
---|
5176 | */
|
---|
5177 | function unmemoize(fn) {
|
---|
5178 | return function () {
|
---|
5179 | return (fn.unmemoized || fn).apply(null, arguments);
|
---|
5180 | };
|
---|
5181 | }
|
---|
5182 |
|
---|
5183 | /**
|
---|
5184 | * Repeatedly call `iteratee`, while `test` returns `true`. Calls `callback` when
|
---|
5185 | * stopped, or an error occurs.
|
---|
5186 | *
|
---|
5187 | * @name whilst
|
---|
5188 | * @static
|
---|
5189 | * @memberOf module:ControlFlow
|
---|
5190 | * @method
|
---|
5191 | * @category Control Flow
|
---|
5192 | * @param {Function} test - synchronous truth test to perform before each
|
---|
5193 | * execution of `iteratee`. Invoked with ().
|
---|
5194 | * @param {AsyncFunction} iteratee - An async function which is called each time
|
---|
5195 | * `test` passes. Invoked with (callback).
|
---|
5196 | * @param {Function} [callback] - A callback which is called after the test
|
---|
5197 | * function has failed and repeated execution of `iteratee` has stopped. `callback`
|
---|
5198 | * will be passed an error and any arguments passed to the final `iteratee`'s
|
---|
5199 | * callback. Invoked with (err, [results]);
|
---|
5200 | * @returns undefined
|
---|
5201 | * @example
|
---|
5202 | *
|
---|
5203 | * var count = 0;
|
---|
5204 | * async.whilst(
|
---|
5205 | * function() { return count < 5; },
|
---|
5206 | * function(callback) {
|
---|
5207 | * count++;
|
---|
5208 | * setTimeout(function() {
|
---|
5209 | * callback(null, count);
|
---|
5210 | * }, 1000);
|
---|
5211 | * },
|
---|
5212 | * function (err, n) {
|
---|
5213 | * // 5 seconds have passed, n = 5
|
---|
5214 | * }
|
---|
5215 | * );
|
---|
5216 | */
|
---|
5217 | function whilst(test, iteratee, callback) {
|
---|
5218 | callback = onlyOnce(callback || noop);
|
---|
5219 | var _iteratee = wrapAsync(iteratee);
|
---|
5220 | if (!test()) return callback(null);
|
---|
5221 | var next = function(err/*, ...args*/) {
|
---|
5222 | if (err) return callback(err);
|
---|
5223 | if (test()) return _iteratee(next);
|
---|
5224 | var args = slice(arguments, 1);
|
---|
5225 | callback.apply(null, [null].concat(args));
|
---|
5226 | };
|
---|
5227 | _iteratee(next);
|
---|
5228 | }
|
---|
5229 |
|
---|
5230 | /**
|
---|
5231 | * Repeatedly call `iteratee` until `test` returns `true`. Calls `callback` when
|
---|
5232 | * stopped, or an error occurs. `callback` will be passed an error and any
|
---|
5233 | * arguments passed to the final `iteratee`'s callback.
|
---|
5234 | *
|
---|
5235 | * The inverse of [whilst]{@link module:ControlFlow.whilst}.
|
---|
5236 | *
|
---|
5237 | * @name until
|
---|
5238 | * @static
|
---|
5239 | * @memberOf module:ControlFlow
|
---|
5240 | * @method
|
---|
5241 | * @see [async.whilst]{@link module:ControlFlow.whilst}
|
---|
5242 | * @category Control Flow
|
---|
5243 | * @param {Function} test - synchronous truth test to perform before each
|
---|
5244 | * execution of `iteratee`. Invoked with ().
|
---|
5245 | * @param {AsyncFunction} iteratee - An async function which is called each time
|
---|
5246 | * `test` fails. Invoked with (callback).
|
---|
5247 | * @param {Function} [callback] - A callback which is called after the test
|
---|
5248 | * function has passed and repeated execution of `iteratee` has stopped. `callback`
|
---|
5249 | * will be passed an error and any arguments passed to the final `iteratee`'s
|
---|
5250 | * callback. Invoked with (err, [results]);
|
---|
5251 | */
|
---|
5252 | function until(test, iteratee, callback) {
|
---|
5253 | whilst(function() {
|
---|
5254 | return !test.apply(this, arguments);
|
---|
5255 | }, iteratee, callback);
|
---|
5256 | }
|
---|
5257 |
|
---|
5258 | /**
|
---|
5259 | * Runs the `tasks` array of functions in series, each passing their results to
|
---|
5260 | * the next in the array. However, if any of the `tasks` pass an error to their
|
---|
5261 | * own callback, the next function is not executed, and the main `callback` is
|
---|
5262 | * immediately called with the error.
|
---|
5263 | *
|
---|
5264 | * @name waterfall
|
---|
5265 | * @static
|
---|
5266 | * @memberOf module:ControlFlow
|
---|
5267 | * @method
|
---|
5268 | * @category Control Flow
|
---|
5269 | * @param {Array} tasks - An array of [async functions]{@link AsyncFunction}
|
---|
5270 | * to run.
|
---|
5271 | * Each function should complete with any number of `result` values.
|
---|
5272 | * The `result` values will be passed as arguments, in order, to the next task.
|
---|
5273 | * @param {Function} [callback] - An optional callback to run once all the
|
---|
5274 | * functions have completed. This will be passed the results of the last task's
|
---|
5275 | * callback. Invoked with (err, [results]).
|
---|
5276 | * @returns undefined
|
---|
5277 | * @example
|
---|
5278 | *
|
---|
5279 | * async.waterfall([
|
---|
5280 | * function(callback) {
|
---|
5281 | * callback(null, 'one', 'two');
|
---|
5282 | * },
|
---|
5283 | * function(arg1, arg2, callback) {
|
---|
5284 | * // arg1 now equals 'one' and arg2 now equals 'two'
|
---|
5285 | * callback(null, 'three');
|
---|
5286 | * },
|
---|
5287 | * function(arg1, callback) {
|
---|
5288 | * // arg1 now equals 'three'
|
---|
5289 | * callback(null, 'done');
|
---|
5290 | * }
|
---|
5291 | * ], function (err, result) {
|
---|
5292 | * // result now equals 'done'
|
---|
5293 | * });
|
---|
5294 | *
|
---|
5295 | * // Or, with named functions:
|
---|
5296 | * async.waterfall([
|
---|
5297 | * myFirstFunction,
|
---|
5298 | * mySecondFunction,
|
---|
5299 | * myLastFunction,
|
---|
5300 | * ], function (err, result) {
|
---|
5301 | * // result now equals 'done'
|
---|
5302 | * });
|
---|
5303 | * function myFirstFunction(callback) {
|
---|
5304 | * callback(null, 'one', 'two');
|
---|
5305 | * }
|
---|
5306 | * function mySecondFunction(arg1, arg2, callback) {
|
---|
5307 | * // arg1 now equals 'one' and arg2 now equals 'two'
|
---|
5308 | * callback(null, 'three');
|
---|
5309 | * }
|
---|
5310 | * function myLastFunction(arg1, callback) {
|
---|
5311 | * // arg1 now equals 'three'
|
---|
5312 | * callback(null, 'done');
|
---|
5313 | * }
|
---|
5314 | */
|
---|
5315 | var waterfall = function(tasks, callback) {
|
---|
5316 | callback = once(callback || noop);
|
---|
5317 | if (!isArray(tasks)) return callback(new Error('First argument to waterfall must be an array of functions'));
|
---|
5318 | if (!tasks.length) return callback();
|
---|
5319 | var taskIndex = 0;
|
---|
5320 |
|
---|
5321 | function nextTask(args) {
|
---|
5322 | var task = wrapAsync(tasks[taskIndex++]);
|
---|
5323 | args.push(onlyOnce(next));
|
---|
5324 | task.apply(null, args);
|
---|
5325 | }
|
---|
5326 |
|
---|
5327 | function next(err/*, ...args*/) {
|
---|
5328 | if (err || taskIndex === tasks.length) {
|
---|
5329 | return callback.apply(null, arguments);
|
---|
5330 | }
|
---|
5331 | nextTask(slice(arguments, 1));
|
---|
5332 | }
|
---|
5333 |
|
---|
5334 | nextTask([]);
|
---|
5335 | };
|
---|
5336 |
|
---|
5337 | /**
|
---|
5338 | * An "async function" in the context of Async is an asynchronous function with
|
---|
5339 | * a variable number of parameters, with the final parameter being a callback.
|
---|
5340 | * (`function (arg1, arg2, ..., callback) {}`)
|
---|
5341 | * The final callback is of the form `callback(err, results...)`, which must be
|
---|
5342 | * called once the function is completed. The callback should be called with a
|
---|
5343 | * Error as its first argument to signal that an error occurred.
|
---|
5344 | * Otherwise, if no error occurred, it should be called with `null` as the first
|
---|
5345 | * argument, and any additional `result` arguments that may apply, to signal
|
---|
5346 | * successful completion.
|
---|
5347 | * The callback must be called exactly once, ideally on a later tick of the
|
---|
5348 | * JavaScript event loop.
|
---|
5349 | *
|
---|
5350 | * This type of function is also referred to as a "Node-style async function",
|
---|
5351 | * or a "continuation passing-style function" (CPS). Most of the methods of this
|
---|
5352 | * library are themselves CPS/Node-style async functions, or functions that
|
---|
5353 | * return CPS/Node-style async functions.
|
---|
5354 | *
|
---|
5355 | * Wherever we accept a Node-style async function, we also directly accept an
|
---|
5356 | * [ES2017 `async` function]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function}.
|
---|
5357 | * In this case, the `async` function will not be passed a final callback
|
---|
5358 | * argument, and any thrown error will be used as the `err` argument of the
|
---|
5359 | * implicit callback, and the return value will be used as the `result` value.
|
---|
5360 | * (i.e. a `rejected` of the returned Promise becomes the `err` callback
|
---|
5361 | * argument, and a `resolved` value becomes the `result`.)
|
---|
5362 | *
|
---|
5363 | * Note, due to JavaScript limitations, we can only detect native `async`
|
---|
5364 | * functions and not transpilied implementations.
|
---|
5365 | * Your environment must have `async`/`await` support for this to work.
|
---|
5366 | * (e.g. Node > v7.6, or a recent version of a modern browser).
|
---|
5367 | * If you are using `async` functions through a transpiler (e.g. Babel), you
|
---|
5368 | * must still wrap the function with [asyncify]{@link module:Utils.asyncify},
|
---|
5369 | * because the `async function` will be compiled to an ordinary function that
|
---|
5370 | * returns a promise.
|
---|
5371 | *
|
---|
5372 | * @typedef {Function} AsyncFunction
|
---|
5373 | * @static
|
---|
5374 | */
|
---|
5375 |
|
---|
5376 | /**
|
---|
5377 | * Async is a utility module which provides straight-forward, powerful functions
|
---|
5378 | * for working with asynchronous JavaScript. Although originally designed for
|
---|
5379 | * use with [Node.js](http://nodejs.org) and installable via
|
---|
5380 | * `npm install --save async`, it can also be used directly in the browser.
|
---|
5381 | * @module async
|
---|
5382 | * @see AsyncFunction
|
---|
5383 | */
|
---|
5384 |
|
---|
5385 |
|
---|
5386 | /**
|
---|
5387 | * A collection of `async` functions for manipulating collections, such as
|
---|
5388 | * arrays and objects.
|
---|
5389 | * @module Collections
|
---|
5390 | */
|
---|
5391 |
|
---|
5392 | /**
|
---|
5393 | * A collection of `async` functions for controlling the flow through a script.
|
---|
5394 | * @module ControlFlow
|
---|
5395 | */
|
---|
5396 |
|
---|
5397 | /**
|
---|
5398 | * A collection of `async` utility functions.
|
---|
5399 | * @module Utils
|
---|
5400 | */
|
---|
5401 |
|
---|
5402 | var index = {
|
---|
5403 | apply: apply,
|
---|
5404 | applyEach: applyEach,
|
---|
5405 | applyEachSeries: applyEachSeries,
|
---|
5406 | asyncify: asyncify,
|
---|
5407 | auto: auto,
|
---|
5408 | autoInject: autoInject,
|
---|
5409 | cargo: cargo,
|
---|
5410 | compose: compose,
|
---|
5411 | concat: concat,
|
---|
5412 | concatLimit: concatLimit,
|
---|
5413 | concatSeries: concatSeries,
|
---|
5414 | constant: constant,
|
---|
5415 | detect: detect,
|
---|
5416 | detectLimit: detectLimit,
|
---|
5417 | detectSeries: detectSeries,
|
---|
5418 | dir: dir,
|
---|
5419 | doDuring: doDuring,
|
---|
5420 | doUntil: doUntil,
|
---|
5421 | doWhilst: doWhilst,
|
---|
5422 | during: during,
|
---|
5423 | each: eachLimit,
|
---|
5424 | eachLimit: eachLimit$1,
|
---|
5425 | eachOf: eachOf,
|
---|
5426 | eachOfLimit: eachOfLimit,
|
---|
5427 | eachOfSeries: eachOfSeries,
|
---|
5428 | eachSeries: eachSeries,
|
---|
5429 | ensureAsync: ensureAsync,
|
---|
5430 | every: every,
|
---|
5431 | everyLimit: everyLimit,
|
---|
5432 | everySeries: everySeries,
|
---|
5433 | filter: filter,
|
---|
5434 | filterLimit: filterLimit,
|
---|
5435 | filterSeries: filterSeries,
|
---|
5436 | forever: forever,
|
---|
5437 | groupBy: groupBy,
|
---|
5438 | groupByLimit: groupByLimit,
|
---|
5439 | groupBySeries: groupBySeries,
|
---|
5440 | log: log,
|
---|
5441 | map: map,
|
---|
5442 | mapLimit: mapLimit,
|
---|
5443 | mapSeries: mapSeries,
|
---|
5444 | mapValues: mapValues,
|
---|
5445 | mapValuesLimit: mapValuesLimit,
|
---|
5446 | mapValuesSeries: mapValuesSeries,
|
---|
5447 | memoize: memoize,
|
---|
5448 | nextTick: nextTick,
|
---|
5449 | parallel: parallelLimit,
|
---|
5450 | parallelLimit: parallelLimit$1,
|
---|
5451 | priorityQueue: priorityQueue,
|
---|
5452 | queue: queue$1,
|
---|
5453 | race: race,
|
---|
5454 | reduce: reduce,
|
---|
5455 | reduceRight: reduceRight,
|
---|
5456 | reflect: reflect,
|
---|
5457 | reflectAll: reflectAll,
|
---|
5458 | reject: reject,
|
---|
5459 | rejectLimit: rejectLimit,
|
---|
5460 | rejectSeries: rejectSeries,
|
---|
5461 | retry: retry,
|
---|
5462 | retryable: retryable,
|
---|
5463 | seq: seq,
|
---|
5464 | series: series,
|
---|
5465 | setImmediate: setImmediate$1,
|
---|
5466 | some: some,
|
---|
5467 | someLimit: someLimit,
|
---|
5468 | someSeries: someSeries,
|
---|
5469 | sortBy: sortBy,
|
---|
5470 | timeout: timeout,
|
---|
5471 | times: times,
|
---|
5472 | timesLimit: timeLimit,
|
---|
5473 | timesSeries: timesSeries,
|
---|
5474 | transform: transform,
|
---|
5475 | tryEach: tryEach,
|
---|
5476 | unmemoize: unmemoize,
|
---|
5477 | until: until,
|
---|
5478 | waterfall: waterfall,
|
---|
5479 | whilst: whilst,
|
---|
5480 |
|
---|
5481 | // aliases
|
---|
5482 | all: every,
|
---|
5483 | allLimit: everyLimit,
|
---|
5484 | allSeries: everySeries,
|
---|
5485 | any: some,
|
---|
5486 | anyLimit: someLimit,
|
---|
5487 | anySeries: someSeries,
|
---|
5488 | find: detect,
|
---|
5489 | findLimit: detectLimit,
|
---|
5490 | findSeries: detectSeries,
|
---|
5491 | forEach: eachLimit,
|
---|
5492 | forEachSeries: eachSeries,
|
---|
5493 | forEachLimit: eachLimit$1,
|
---|
5494 | forEachOf: eachOf,
|
---|
5495 | forEachOfSeries: eachOfSeries,
|
---|
5496 | forEachOfLimit: eachOfLimit,
|
---|
5497 | inject: reduce,
|
---|
5498 | foldl: reduce,
|
---|
5499 | foldr: reduceRight,
|
---|
5500 | select: filter,
|
---|
5501 | selectLimit: filterLimit,
|
---|
5502 | selectSeries: filterSeries,
|
---|
5503 | wrapSync: asyncify
|
---|
5504 | };
|
---|
5505 |
|
---|
5506 | exports['default'] = index;
|
---|
5507 | exports.apply = apply;
|
---|
5508 | exports.applyEach = applyEach;
|
---|
5509 | exports.applyEachSeries = applyEachSeries;
|
---|
5510 | exports.asyncify = asyncify;
|
---|
5511 | exports.auto = auto;
|
---|
5512 | exports.autoInject = autoInject;
|
---|
5513 | exports.cargo = cargo;
|
---|
5514 | exports.compose = compose;
|
---|
5515 | exports.concat = concat;
|
---|
5516 | exports.concatLimit = concatLimit;
|
---|
5517 | exports.concatSeries = concatSeries;
|
---|
5518 | exports.constant = constant;
|
---|
5519 | exports.detect = detect;
|
---|
5520 | exports.detectLimit = detectLimit;
|
---|
5521 | exports.detectSeries = detectSeries;
|
---|
5522 | exports.dir = dir;
|
---|
5523 | exports.doDuring = doDuring;
|
---|
5524 | exports.doUntil = doUntil;
|
---|
5525 | exports.doWhilst = doWhilst;
|
---|
5526 | exports.during = during;
|
---|
5527 | exports.each = eachLimit;
|
---|
5528 | exports.eachLimit = eachLimit$1;
|
---|
5529 | exports.eachOf = eachOf;
|
---|
5530 | exports.eachOfLimit = eachOfLimit;
|
---|
5531 | exports.eachOfSeries = eachOfSeries;
|
---|
5532 | exports.eachSeries = eachSeries;
|
---|
5533 | exports.ensureAsync = ensureAsync;
|
---|
5534 | exports.every = every;
|
---|
5535 | exports.everyLimit = everyLimit;
|
---|
5536 | exports.everySeries = everySeries;
|
---|
5537 | exports.filter = filter;
|
---|
5538 | exports.filterLimit = filterLimit;
|
---|
5539 | exports.filterSeries = filterSeries;
|
---|
5540 | exports.forever = forever;
|
---|
5541 | exports.groupBy = groupBy;
|
---|
5542 | exports.groupByLimit = groupByLimit;
|
---|
5543 | exports.groupBySeries = groupBySeries;
|
---|
5544 | exports.log = log;
|
---|
5545 | exports.map = map;
|
---|
5546 | exports.mapLimit = mapLimit;
|
---|
5547 | exports.mapSeries = mapSeries;
|
---|
5548 | exports.mapValues = mapValues;
|
---|
5549 | exports.mapValuesLimit = mapValuesLimit;
|
---|
5550 | exports.mapValuesSeries = mapValuesSeries;
|
---|
5551 | exports.memoize = memoize;
|
---|
5552 | exports.nextTick = nextTick;
|
---|
5553 | exports.parallel = parallelLimit;
|
---|
5554 | exports.parallelLimit = parallelLimit$1;
|
---|
5555 | exports.priorityQueue = priorityQueue;
|
---|
5556 | exports.queue = queue$1;
|
---|
5557 | exports.race = race;
|
---|
5558 | exports.reduce = reduce;
|
---|
5559 | exports.reduceRight = reduceRight;
|
---|
5560 | exports.reflect = reflect;
|
---|
5561 | exports.reflectAll = reflectAll;
|
---|
5562 | exports.reject = reject;
|
---|
5563 | exports.rejectLimit = rejectLimit;
|
---|
5564 | exports.rejectSeries = rejectSeries;
|
---|
5565 | exports.retry = retry;
|
---|
5566 | exports.retryable = retryable;
|
---|
5567 | exports.seq = seq;
|
---|
5568 | exports.series = series;
|
---|
5569 | exports.setImmediate = setImmediate$1;
|
---|
5570 | exports.some = some;
|
---|
5571 | exports.someLimit = someLimit;
|
---|
5572 | exports.someSeries = someSeries;
|
---|
5573 | exports.sortBy = sortBy;
|
---|
5574 | exports.timeout = timeout;
|
---|
5575 | exports.times = times;
|
---|
5576 | exports.timesLimit = timeLimit;
|
---|
5577 | exports.timesSeries = timesSeries;
|
---|
5578 | exports.transform = transform;
|
---|
5579 | exports.tryEach = tryEach;
|
---|
5580 | exports.unmemoize = unmemoize;
|
---|
5581 | exports.until = until;
|
---|
5582 | exports.waterfall = waterfall;
|
---|
5583 | exports.whilst = whilst;
|
---|
5584 | exports.all = every;
|
---|
5585 | exports.allLimit = everyLimit;
|
---|
5586 | exports.allSeries = everySeries;
|
---|
5587 | exports.any = some;
|
---|
5588 | exports.anyLimit = someLimit;
|
---|
5589 | exports.anySeries = someSeries;
|
---|
5590 | exports.find = detect;
|
---|
5591 | exports.findLimit = detectLimit;
|
---|
5592 | exports.findSeries = detectSeries;
|
---|
5593 | exports.forEach = eachLimit;
|
---|
5594 | exports.forEachSeries = eachSeries;
|
---|
5595 | exports.forEachLimit = eachLimit$1;
|
---|
5596 | exports.forEachOf = eachOf;
|
---|
5597 | exports.forEachOfSeries = eachOfSeries;
|
---|
5598 | exports.forEachOfLimit = eachOfLimit;
|
---|
5599 | exports.inject = reduce;
|
---|
5600 | exports.foldl = reduce;
|
---|
5601 | exports.foldr = reduceRight;
|
---|
5602 | exports.select = filter;
|
---|
5603 | exports.selectLimit = filterLimit;
|
---|
5604 | exports.selectSeries = filterSeries;
|
---|
5605 | exports.wrapSync = asyncify;
|
---|
5606 |
|
---|
5607 | Object.defineProperty(exports, '__esModule', { value: true });
|
---|
5608 |
|
---|
5609 | })));
|
---|