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