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