summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Early <alexander.early@gmail.com>2017-04-02 15:23:08 -0700
committerGitHub <noreply@github.com>2017-04-02 15:23:08 -0700
commit49119a895d64991375d1a7b82b3a4d71e3ec8681 (patch)
tree6eb966f6115913e2820e173d2b5ddaa58feb04ac
parent66b3c727762e4bf4909e6d8c5e6312810b384204 (diff)
parent8faed87d71496776c7100dc29f2a8e294261c820 (diff)
downloadasync-49119a895d64991375d1a7b82b3a4d71e3ec8681.tar.gz
Merge pull request #1390 from caolan/async-fn-support
`async` function support
-rw-r--r--.eslintrc2
-rw-r--r--.travis.yml8
-rw-r--r--dist/async.js188
-rw-r--r--lib/applyEach.js2
-rw-r--r--lib/applyEachSeries.js2
-rw-r--r--lib/asyncify.js13
-rw-r--r--lib/auto.js11
-rw-r--r--lib/autoInject.js19
-rw-r--r--lib/cargo.js5
-rw-r--r--lib/compose.js2
-rw-r--r--lib/concat.js6
-rw-r--r--lib/concatSeries.js5
-rw-r--r--lib/constant.js2
-rw-r--r--lib/detect.js6
-rw-r--r--lib/detectLimit.js6
-rw-r--r--lib/detectSeries.js6
-rw-r--r--lib/dir.js13
-rw-r--r--lib/doDuring.js14
-rw-r--r--lib/doUntil.js16
-rw-r--r--lib/doWhilst.js13
-rw-r--r--lib/during.js16
-rw-r--r--lib/each.js13
-rw-r--r--lib/eachLimit.js14
-rw-r--r--lib/eachOf.js13
-rw-r--r--lib/eachOfLimit.js11
-rw-r--r--lib/eachOfSeries.js8
-rw-r--r--lib/eachSeries.js11
-rw-r--r--lib/ensureAsync.js9
-rw-r--r--lib/every.js8
-rw-r--r--lib/everyLimit.js8
-rw-r--r--lib/everySeries.js8
-rw-r--r--lib/forever.js11
-rw-r--r--lib/groupBy.js8
-rw-r--r--lib/groupByLimit.js14
-rw-r--r--lib/groupBySeries.js8
-rw-r--r--lib/index.js50
-rw-r--r--lib/internal/applyEach.js3
-rw-r--r--lib/internal/consoleFunc.js3
-rw-r--r--lib/internal/doParallel.js3
-rw-r--r--lib/internal/doParallelLimit.js3
-rw-r--r--lib/internal/doSeries.js3
-rw-r--r--lib/internal/filter.js4
-rw-r--r--lib/internal/map.js4
-rw-r--r--lib/internal/parallel.js3
-rw-r--r--lib/internal/queue.js23
-rw-r--r--lib/internal/wrapAsync.js27
-rw-r--r--lib/log.js4
-rw-r--r--lib/map.js8
-rw-r--r--lib/mapLimit.js8
-rw-r--r--lib/mapSeries.js8
-rw-r--r--lib/mapValues.js8
-rw-r--r--lib/mapValuesLimit.js12
-rw-r--r--lib/mapValuesSeries.js8
-rw-r--r--lib/memoize.js10
-rw-r--r--lib/parallel.js9
-rw-r--r--lib/parallelLimit.js7
-rw-r--r--lib/priorityQueue.js9
-rw-r--r--lib/queue.js12
-rw-r--r--lib/race.js8
-rw-r--r--lib/reduce.js16
-rw-r--r--lib/reduceRight.js12
-rw-r--r--lib/reflect.js12
-rw-r--r--lib/reflectAll.js7
-rw-r--r--lib/reject.js7
-rw-r--r--lib/rejectLimit.js7
-rw-r--r--lib/rejectSeries.js7
-rw-r--r--lib/retry.js17
-rw-r--r--lib/retryable.js18
-rw-r--r--lib/seq.js7
-rw-r--r--lib/series.js6
-rw-r--r--lib/some.js8
-rw-r--r--lib/someLimit.js8
-rw-r--r--lib/someSeries.js8
-rw-r--r--lib/sortBy.js13
-rw-r--r--lib/timeout.js14
-rw-r--r--lib/times.js4
-rw-r--r--lib/timesLimit.js8
-rw-r--r--lib/timesSeries.js4
-rw-r--r--lib/transform.js11
-rw-r--r--lib/unmemoize.js4
-rw-r--r--lib/until.js19
-rw-r--r--lib/waterfall.js11
-rw-r--r--lib/whilst.js11
-rw-r--r--mocha_test/asyncFunctions.js11
-rw-r--r--mocha_test/es2017/asyncFunctions.js682
-rw-r--r--package.json5
86 files changed, 1256 insertions, 417 deletions
diff --git a/.eslintrc b/.eslintrc
index 2644f5c..2627332 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -6,7 +6,7 @@
"es6": true
},
"parserOptions": {
- "ecmaVersion": 6,
+ "ecmaVersion": 8,
"sourceType": "module"
},
"rules": {
diff --git a/.travis.yml b/.travis.yml
index ff46739..6732369 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,12 +4,14 @@ node_js:
- "0.10"
- "0.12"
- "4"
+ - "6"
+ - "7"
matrix:
include:
- - node_js: "6"
+ - node_js: "7"
addons:
- firefox: "49.0"
+ firefox: "52.0"
env: BROWSER=true MAKE_TEST=true
env:
matrix: BROWSER=false MAKE_TEST=false
@@ -27,4 +29,4 @@ script:
# ensure buildable
- "[ $MAKE_TEST == false ] || make"
# test in firefox
- - "[ $BROWSER == false ] || npm run mocha-browser-test" \ No newline at end of file
+ - "[ $BROWSER == false ] || npm run mocha-browser-test"
diff --git a/dist/async.js b/dist/async.js
index 155d779..6e4ef32 100644
--- a/dist/async.js
+++ b/dist/async.js
@@ -888,6 +888,105 @@ function _eachOfLimit(limit) {
}
/**
+ * Take a sync function and make it async, passing its return value to a
+ * callback. This is useful for plugging sync functions into a waterfall,
+ * series, or other async functions. Any arguments passed to the generated
+ * function will be passed to the wrapped function (except for the final
+ * callback argument). Errors thrown will be passed to the callback.
+ *
+ * If the function passed to `asyncify` returns a Promise, that promises's
+ * resolved/rejected state will be used to call the callback, rather than simply
+ * the synchronous return value.
+ *
+ * This also means you can asyncify ES2016 `async` functions.
+ *
+ * @name asyncify
+ * @static
+ * @memberOf module:Utils
+ * @method
+ * @alias wrapSync
+ * @category Util
+ * @param {Function} func - The synchronous function to convert to an
+ * asynchronous function.
+ * @returns {Function} An asynchronous wrapper of the `func`. To be invoked with
+ * (callback).
+ * @example
+ *
+ * // passing a regular synchronous function
+ * async.waterfall([
+ * async.apply(fs.readFile, filename, "utf8"),
+ * async.asyncify(JSON.parse),
+ * function (data, next) {
+ * // data is the result of parsing the text.
+ * // If there was a parsing error, it would have been caught.
+ * }
+ * ], callback);
+ *
+ * // passing a function returning a promise
+ * async.waterfall([
+ * async.apply(fs.readFile, filename, "utf8"),
+ * async.asyncify(function (contents) {
+ * return db.model.create(contents);
+ * }),
+ * function (model, next) {
+ * // `model` is the instantiated model object.
+ * // If there was an error, this function would be skipped.
+ * }
+ * ], callback);
+ *
+ * // es2017 example
+ * var q = async.queue(async.asyncify(async function(file) {
+ * var intermediateStep = await processFile(file);
+ * return await somePromise(intermediateStep)
+ * }));
+ *
+ * q.push(files);
+ */
+function asyncify(func) {
+ return initialParams(function (args, callback) {
+ var result;
+ try {
+ result = func.apply(this, args);
+ } catch (e) {
+ return callback(e);
+ }
+ // if result is Promise object
+ if (isObject(result) && typeof result.then === 'function') {
+ result.then(function (value) {
+ callback(null, value);
+ }, function (err) {
+ callback(err.message ? err : new Error(err));
+ });
+ } else {
+ callback(null, result);
+ }
+ });
+}
+
+var supportsSymbol = typeof Symbol !== 'undefined';
+
+function supportsAsync() {
+ var supported;
+ try {
+ /* eslint no-eval: 0 */
+ supported = supportsSymbol && isAsync(eval('(async function () {})'));
+ } catch (e) {
+ supported = false;
+ }
+ return supported;
+}
+
+function isAsync(fn) {
+ return fn[Symbol.toStringTag] === 'AsyncFunction';
+}
+
+var wrapAsync$1 = supportsAsync() ? function wrapAsync(asyncFn) {
+ if (!supportsSymbol) return asyncFn;
+
+ return isAsync(asyncFn) ? asyncify(asyncFn) : asyncFn;
+} : identity;
+
+/**
* The same as [`eachOf`]{@link module:Collections.eachOf} but runs a maximum of `limit` async operations at a
* time.
*
@@ -910,7 +1009,7 @@ function _eachOfLimit(limit) {
* `iteratee` functions have finished, or an error occurs. Invoked with (err).
*/
function eachOfLimit(coll, limit, iteratee, callback) {
- _eachOfLimit(limit)(coll, iteratee, callback);
+ _eachOfLimit(limit)(coll, wrapAsync$1(iteratee), callback);
}
function doLimit(fn, limit) {
@@ -988,7 +1087,7 @@ var eachOfGeneric = doLimit(eachOfLimit, Infinity);
*/
var eachOf = function (coll, iteratee, callback) {
var eachOfImplementation = isArrayLike(coll) ? eachOfArrayLike : eachOfGeneric;
- eachOfImplementation(coll, iteratee, callback);
+ eachOfImplementation(coll, wrapAsync$1(iteratee), callback);
};
function doParallel(fn) {
@@ -1002,10 +1101,11 @@ function _asyncMap(eachfn, arr, iteratee, callback) {
arr = arr || [];
var results = [];
var counter = 0;
+ var _iteratee = wrapAsync$1(iteratee);
eachfn(arr, function (value, _, callback) {
var index = counter++;
- iteratee(value, function (err, v) {
+ _iteratee(value, function (err, v) {
results[index] = v;
callback(err);
});
@@ -1206,82 +1306,6 @@ var apply$2 = rest(function (fn, args) {
});
/**
- * Take a sync function and make it async, passing its return value to a
- * callback. This is useful for plugging sync functions into a waterfall,
- * series, or other async functions. Any arguments passed to the generated
- * function will be passed to the wrapped function (except for the final
- * callback argument). Errors thrown will be passed to the callback.
- *
- * If the function passed to `asyncify` returns a Promise, that promises's
- * resolved/rejected state will be used to call the callback, rather than simply
- * the synchronous return value.
- *
- * This also means you can asyncify ES2016 `async` functions.
- *
- * @name asyncify
- * @static
- * @memberOf module:Utils
- * @method
- * @alias wrapSync
- * @category Util
- * @param {Function} func - The synchronous function to convert to an
- * asynchronous function.
- * @returns {Function} An asynchronous wrapper of the `func`. To be invoked with
- * (callback).
- * @example
- *
- * // passing a regular synchronous function
- * async.waterfall([
- * async.apply(fs.readFile, filename, "utf8"),
- * async.asyncify(JSON.parse),
- * function (data, next) {
- * // data is the result of parsing the text.
- * // If there was a parsing error, it would have been caught.
- * }
- * ], callback);
- *
- * // passing a function returning a promise
- * async.waterfall([
- * async.apply(fs.readFile, filename, "utf8"),
- * async.asyncify(function (contents) {
- * return db.model.create(contents);
- * }),
- * function (model, next) {
- * // `model` is the instantiated model object.
- * // If there was an error, this function would be skipped.
- * }
- * ], callback);
- *
- * // es6 example
- * var q = async.queue(async.asyncify(async function(file) {
- * var intermediateStep = await processFile(file);
- * return await somePromise(intermediateStep)
- * }));
- *
- * q.push(files);
- */
-function asyncify(func) {
- return initialParams(function (args, callback) {
- var result;
- try {
- result = func.apply(this, args);
- } catch (e) {
- return callback(e);
- }
- // if result is Promise object
- if (isObject(result) && typeof result.then === 'function') {
- result.then(function (value) {
- callback(null, value);
- }, function (err) {
- callback(err.message ? err : new Error(err));
- });
- } else {
- callback(null, result);
- }
- });
-}
-
-/**
* A specialized version of `_.forEach` for arrays without support for
* iteratee shorthands.
*
@@ -3083,7 +3107,7 @@ function _withoutIndex(iteratee) {
* });
*/
function eachLimit(coll, iteratee, callback) {
- eachOf(coll, _withoutIndex(iteratee), callback);
+ eachOf(coll, _withoutIndex(wrapAsync$1(iteratee)), callback);
}
/**
@@ -3108,7 +3132,7 @@ function eachLimit(coll, iteratee, callback) {
* `iteratee` functions have finished, or an error occurs. Invoked with (err).
*/
function eachLimit$1(coll, limit, iteratee, callback) {
- _eachOfLimit(limit)(coll, _withoutIndex(iteratee), callback);
+ _eachOfLimit(limit)(coll, _withoutIndex(wrapAsync$1(iteratee)), callback);
}
/**
@@ -3318,7 +3342,7 @@ function filterGeneric(eachfn, coll, iteratee, callback) {
function _filter(eachfn, coll, iteratee, callback) {
var filter = isArrayLike(coll) ? filterArray : filterGeneric;
- filter(eachfn, coll, iteratee, callback || noop);
+ filter(eachfn, coll, wrapAsync$1(iteratee), callback || noop);
}
/**
diff --git a/lib/applyEach.js b/lib/applyEach.js
index d1dfc78..93d8af3 100644
--- a/lib/applyEach.js
+++ b/lib/applyEach.js
@@ -13,7 +13,7 @@ import map from './map';
* @memberOf module:ControlFlow
* @method
* @category Control Flow
- * @param {Array|Iterable|Object} fns - A collection of asynchronous functions
+ * @param {Array|Iterable|Object} fns - A collection of {@link AsyncFunction}s
* to all call with the same arguments
* @param {...*} [args] - any number of separate arguments to pass to the
* function.
diff --git a/lib/applyEachSeries.js b/lib/applyEachSeries.js
index 5a7c257..392b139 100644
--- a/lib/applyEachSeries.js
+++ b/lib/applyEachSeries.js
@@ -10,7 +10,7 @@ import mapSeries from './mapSeries';
* @method
* @see [async.applyEach]{@link module:ControlFlow.applyEach}
* @category Control Flow
- * @param {Array|Iterable|Object} fns - A collection of asynchronous functions to all
+ * @param {Array|Iterable|Object} fns - A collection of {@link AsyncFunction}s to all
* call with the same arguments
* @param {...*} [args] - any number of separate arguments to pass to the
* function.
diff --git a/lib/asyncify.js b/lib/asyncify.js
index dec39d2..96eea54 100644
--- a/lib/asyncify.js
+++ b/lib/asyncify.js
@@ -12,7 +12,7 @@ import initialParams from './internal/initialParams';
* resolved/rejected state will be used to call the callback, rather than simply
* the synchronous return value.
*
- * This also means you can asyncify ES2016 `async` functions.
+ * This also means you can asyncify ES2017 `async` functions.
*
* @name asyncify
* @static
@@ -20,10 +20,10 @@ import initialParams from './internal/initialParams';
* @method
* @alias wrapSync
* @category Util
- * @param {Function} func - The synchronous function to convert to an
- * asynchronous function.
- * @returns {Function} An asynchronous wrapper of the `func`. To be invoked with
- * (callback).
+ * @param {Function} func - The synchronous funuction, or Promise-returning
+ * function to convert to an {@link AsyncFunction}.
+ * @returns {AsyncFunction} An asynchronous wrapper of the `func`. To be
+ * invoked with `(args..., callback)`.
* @example
*
* // passing a regular synchronous function
@@ -48,7 +48,8 @@ import initialParams from './internal/initialParams';
* }
* ], callback);
*
- * // es6 example
+ * // es2017 example, though `asyncify` is not needed if your JS environment
+ * // supports async functions out of the box
* var q = async.queue(async.asyncify(async function(file) {
* var intermediateStep = await processFile(file);
* return await somePromise(intermediateStep)
diff --git a/lib/auto.js b/lib/auto.js
index fe98e06..ba0fdc3 100644
--- a/lib/auto.js
+++ b/lib/auto.js
@@ -8,19 +8,20 @@ import rest from './internal/rest';
import once from './internal/once';
import onlyOnce from './internal/onlyOnce';
+import wrapAsync from './internal/wrapAsync';
/**
- * Determines the best order for running the functions in `tasks`, based on
+ * Determines the best order for running the {@link AsyncFunction}s in `tasks`, based on
* their requirements. Each function can optionally depend on other functions
* being completed first, and each function is run as soon as its requirements
* are satisfied.
*
- * If any of the functions pass an error to their callback, the `auto` sequence
+ * If any of the {@link AsyncFunction}s pass an error to their callback, the `auto` sequence
* will stop. Further tasks will not execute (so any other functions depending
* on it will not run), and the main `callback` is immediately called with the
* error.
*
- * Functions also receive an object containing the results of functions which
+ * {@link AsyncFunction}s also receive an object containing the results of functions which
* have completed so far as the first argument, if they have dependencies. If a
* task function has no dependencies, it will only be passed a callback.
*
@@ -30,7 +31,7 @@ import onlyOnce from './internal/onlyOnce';
* @method
* @category Control Flow
* @param {Object} tasks - An object. Each of its properties is either a
- * function or an array of requirements, with the function itself the last item
+ * function or an array of requirements, with the {@link AsyncFunction} itself the last item
* in the array. The object's key of a property serves as the name of the task
* defined by that property, i.e. can be used when specifying requirements for
* other tasks. The function receives one or two arguments:
@@ -213,7 +214,7 @@ export default function (tasks, concurrency, callback) {
}));
runningTasks++;
- var taskFn = task[task.length - 1];
+ var taskFn = wrapAsync(task[task.length - 1]);
if (task.length > 1) {
taskFn(results, taskCallback);
} else {
diff --git a/lib/autoInject.js b/lib/autoInject.js
index b0f5735..bc8ddd6 100644
--- a/lib/autoInject.js
+++ b/lib/autoInject.js
@@ -3,8 +3,10 @@ import forOwn from 'lodash/_baseForOwn';
import arrayMap from 'lodash/_arrayMap';
import isArray from 'lodash/isArray';
import trim from 'lodash/trim';
+import wrapAsync from './internal/wrapAsync';
+import { isAsync } from './internal/wrapAsync';
-var FN_ARGS = /^(function)?\s*[^\(]*\(\s*([^\)]*)\)/m;
+var FN_ARGS = /^(?:async\s+)?(function)?\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /(=.+)?(\s*)$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
@@ -38,7 +40,7 @@ function parseParams(func) {
* @method
* @see [async.auto]{@link module:ControlFlow.auto}
* @category Control Flow
- * @param {Object} tasks - An object, each of whose properties is a function of
+ * @param {Object} tasks - An object, each of whose properties is an {@link AsyncFunction} of
* the form 'func([dependencies...], callback). The object's key of a property
* serves as the name of the task defined by that property, i.e. can be used
* when specifying requirements for other tasks.
@@ -106,22 +108,27 @@ export default function autoInject(tasks, callback) {
forOwn(tasks, function (taskFn, key) {
var params;
+ var fnIsAsync = isAsync(taskFn);
+ var hasNoDeps =
+ (!fnIsAsync && taskFn.length === 1) ||
+ (fnIsAsync && taskFn.length === 0);
if (isArray(taskFn)) {
params = taskFn.slice(0, -1);
taskFn = taskFn[taskFn.length - 1];
newTasks[key] = params.concat(params.length > 0 ? newTask : taskFn);
- } else if (taskFn.length === 1) {
+ } else if (hasNoDeps) {
// no dependencies, use the function as-is
newTasks[key] = taskFn;
} else {
params = parseParams(taskFn);
- if (taskFn.length === 0 && params.length === 0) {
+ if (taskFn.length === 0 && !fnIsAsync && params.length === 0) {
throw new Error("autoInject task functions require explicit parameters.");
}
- params.pop();
+ // remove callback param
+ if (!fnIsAsync) params.pop();
newTasks[key] = params.concat(newTask);
}
@@ -131,7 +138,7 @@ export default function autoInject(tasks, callback) {
return results[name];
});
newArgs.push(taskCb);
- taskFn.apply(null, newArgs);
+ wrapAsync(taskFn).apply(null, newArgs);
}
});
diff --git a/lib/cargo.js b/lib/cargo.js
index d86cb67..5060223 100644
--- a/lib/cargo.js
+++ b/lib/cargo.js
@@ -48,9 +48,8 @@ import queue from './internal/queue';
* @method
* @see [async.queue]{@link module:ControlFlow.queue}
* @category Control Flow
- * @param {Function} worker - An asynchronous function for processing an array
- * of queued tasks, which must call its `callback(err)` argument when finished,
- * with an optional `err` argument. Invoked with `(tasks, callback)`.
+ * @param {AsyncFunction} worker - An asynchronous function for processing an array
+ * of queued tasks. Invoked with `(tasks, callback)`.
* @param {number} [payload=Infinity] - An optional `integer` for determining
* how many tasks should be processed per round; if omitted, the default is
* unlimited.
diff --git a/lib/compose.js b/lib/compose.js
index 5c64593..96632c0 100644
--- a/lib/compose.js
+++ b/lib/compose.js
@@ -14,7 +14,7 @@ import rest from './internal/rest';
* @memberOf module:ControlFlow
* @method
* @category Control Flow
- * @param {...Function} functions - the asynchronous functions to compose
+ * @param {...AsyncFunction} functions - the asynchronous functions to compose
* @returns {Function} an asynchronous function that is the composed
* asynchronous `functions`
* @example
diff --git a/lib/concat.js b/lib/concat.js
index ba4ea13..7edf759 100644
--- a/lib/concat.js
+++ b/lib/concat.js
@@ -14,10 +14,8 @@ import doParallel from './internal/doParallel';
* @method
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A function to apply to each item in `coll`.
- * The iteratee is passed a `callback(err, results)` which must be called once
- * it has completed with an error (which can be `null`) and an array of results.
- * Invoked with (item, callback).
+ * @param {AsyncFunction} iteratee - A function to apply to each item in `coll`,
+ * which should use an array as its result. Invoked with (item, callback).
* @param {Function} [callback(err)] - A callback which is called after all the
* `iteratee` functions have finished, or an error occurs. Results is an array
* containing the concatenated results of the `iteratee` function. Invoked with
diff --git a/lib/concatSeries.js b/lib/concatSeries.js
index 77b439b..f5b3fab 100644
--- a/lib/concatSeries.js
+++ b/lib/concatSeries.js
@@ -11,9 +11,8 @@ import doSeries from './internal/doSeries';
* @see [async.concat]{@link module:Collections.concat}
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A function to apply to each item in `coll`.
- * The iteratee is passed a `callback(err, results)` which must be called once
- * it has completed with an error (which can be `null`) and an array of results.
+ * @param {AsyncFunction} iteratee - A function to apply to each item in `coll`.
+ * The iteratee should complete with an array an array of results.
* Invoked with (item, callback).
* @param {Function} [callback(err)] - A callback which is called after all the
* `iteratee` functions have finished, or an error occurs. Results is an array
diff --git a/lib/constant.js b/lib/constant.js
index c9c0c1e..ae6ffd0 100644
--- a/lib/constant.js
+++ b/lib/constant.js
@@ -13,7 +13,7 @@ import initialParams from './internal/initialParams';
* @category Util
* @param {...*} arguments... - Any number of arguments to automatically invoke
* callback with.
- * @returns {Function} Returns a function that when invoked, automatically
+ * @returns {AsyncFunction} Returns a function that when invoked, automatically
* invokes the callback with the previous given arguments.
* @example
*
diff --git a/lib/detect.js b/lib/detect.js
index 5f5a7ef..654a370 100644
--- a/lib/detect.js
+++ b/lib/detect.js
@@ -21,9 +21,9 @@ import findGetResult from './internal/findGetResult';
* @alias find
* @category Collections
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A truth test to apply to each item in `coll`.
- * The iteratee is passed a `callback(err, truthValue)` which must be called
- * with a boolean argument once it has completed. Invoked with (item, callback).
+ * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.
+ * The iteratee must complete with a boolean value as its result.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called as soon as any
* iteratee returns `true`, or after all the `iteratee` functions have finished.
* Result will be the first item in the array that passes the truth test
diff --git a/lib/detectLimit.js b/lib/detectLimit.js
index d0f2a92..bba10c8 100644
--- a/lib/detectLimit.js
+++ b/lib/detectLimit.js
@@ -17,9 +17,9 @@ import findGetResult from './internal/findGetResult';
* @category Collections
* @param {Array|Iterable|Object} coll - A collection to iterate over.
* @param {number} limit - The maximum number of async operations at a time.
- * @param {Function} iteratee - A truth test to apply to each item in `coll`.
- * The iteratee is passed a `callback(err, truthValue)` which must be called
- * with a boolean argument once it has completed. Invoked with (item, callback).
+ * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.
+ * The iteratee must complete with a boolean value as its result.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called as soon as any
* iteratee returns `true`, or after all the `iteratee` functions have finished.
* Result will be the first item in the array that passes the truth test
diff --git a/lib/detectSeries.js b/lib/detectSeries.js
index 51413df..684bdaa 100644
--- a/lib/detectSeries.js
+++ b/lib/detectSeries.js
@@ -12,9 +12,9 @@ import doLimit from './internal/doLimit';
* @alias findSeries
* @category Collections
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A truth test to apply to each item in `coll`.
- * The iteratee is passed a `callback(err, truthValue)` which must be called
- * with a boolean argument once it has completed. Invoked with (item, callback).
+ * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.
+ * The iteratee must complete with a boolean value as its result.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called as soon as any
* iteratee returns `true`, or after all the `iteratee` functions have finished.
* Result will be the first item in the array that passes the truth test
diff --git a/lib/dir.js b/lib/dir.js
index 912b558..8a5b5e3 100644
--- a/lib/dir.js
+++ b/lib/dir.js
@@ -1,10 +1,11 @@
import consoleFunc from './internal/consoleFunc';
/**
- * Logs the result of an `async` function to the `console` using `console.dir`
- * to display the properties of the resulting object. Only works in Node.js or
- * in browsers that support `console.dir` and `console.error` (such as FF and
- * Chrome). If multiple arguments are returned from the async function,
+ * Logs the result of an [`async` function]{@link AsyncFunction} to the
+ * `console` using `console.dir` to display the properties of the resulting object.
+ * Only works in Node.js or in browsers that support `console.dir` and
+ * `console.error` (such as FF and Chrome).
+ * If multiple arguments are returned from the async function,
* `console.dir` is called on each argument in order.
*
* @name dir
@@ -12,8 +13,8 @@ import consoleFunc from './internal/consoleFunc';
* @memberOf module:Utils
* @method
* @category Util
- * @param {Function} function - The function you want to eventually apply all
- * arguments to.
+ * @param {AsyncFunction} function - The function you want to eventually apply
+ * all arguments to.
* @param {...*} arguments... - Any number of arguments to apply to the function.
* @example
*
diff --git a/lib/doDuring.js b/lib/doDuring.js
index 6e80f54..85a69c2 100644
--- a/lib/doDuring.js
+++ b/lib/doDuring.js
@@ -1,6 +1,7 @@
import noop from 'lodash/noop';
import rest from './internal/rest';
import onlyOnce from './internal/onlyOnce';
+import wrapAsync from './internal/wrapAsync';
/**
* The post-check version of [`during`]{@link module:ControlFlow.during}. To reflect the difference in
@@ -13,10 +14,9 @@ import onlyOnce from './internal/onlyOnce';
* @method
* @see [async.during]{@link module:ControlFlow.during}
* @category Control Flow
- * @param {Function} fn - A function which is called each time `test` passes.
- * The function is passed a `callback(err)`, which must be called once it has
- * completed with an optional `err` argument. Invoked with (callback).
- * @param {Function} test - asynchronous truth test to perform before each
+ * @param {AsyncFunction} fn - An async function which is called each time
+ * `test` passes. Invoked with (callback).
+ * @param {AsyncFunction} test - asynchronous truth test to perform before each
* execution of `fn`. Invoked with (...args, callback), where `...args` are the
* non-error args from the previous callback of `fn`.
* @param {Function} [callback] - A callback which is called after the test
@@ -25,17 +25,19 @@ import onlyOnce from './internal/onlyOnce';
*/
export default function doDuring(fn, test, callback) {
callback = onlyOnce(callback || noop);
+ var _fn = wrapAsync(fn);
+ var _test = wrapAsync(test);
var next = rest(function(err, args) {
if (err) return callback(err);
args.push(check);
- test.apply(this, args);
+ _test.apply(this, args);
});
function check(err, truth) {
if (err) return callback(err);
if (!truth) return callback(null);
- fn(next);
+ _fn(next);
}
check(null, true);
diff --git a/lib/doUntil.js b/lib/doUntil.js
index 0c5bb71..06d3af7 100644
--- a/lib/doUntil.js
+++ b/lib/doUntil.js
@@ -10,18 +10,18 @@ import doWhilst from './doWhilst';
* @method
* @see [async.doWhilst]{@link module:ControlFlow.doWhilst}
* @category Control Flow
- * @param {Function} fn - A function which is called each time `test` fails.
- * The function is passed a `callback(err)`, which must be called once it has
- * completed with an optional `err` argument. Invoked with (callback).
+ * @param {AsyncFunction} iteratee - An async function which is called each time
+ * `test` fails. Invoked with (callback).
* @param {Function} test - synchronous truth test to perform after each
- * execution of `fn`. Invoked with the non-error callback results of `fn`.
+ * execution of `iteratee`. Invoked with any non-error callback results of
+ * `iteratee`.
* @param {Function} [callback] - A callback which is called after the test
- * function has passed and repeated execution of `fn` has stopped. `callback`
- * will be passed an error and any arguments passed to the final `fn`'s
+ * function has passed and repeated execution of `iteratee` has stopped. `callback`
+ * will be passed an error and any arguments passed to the final `iteratee`'s
* callback. Invoked with (err, [results]);
*/
-export default function doUntil(fn, test, callback) {
- doWhilst(fn, function() {
+export default function doUntil(iteratee, test, callback) {
+ doWhilst(iteratee, function() {
return !test.apply(this, arguments);
}, callback);
}
diff --git a/lib/doWhilst.js b/lib/doWhilst.js
index d9222aa..4407305 100644
--- a/lib/doWhilst.js
+++ b/lib/doWhilst.js
@@ -2,6 +2,7 @@ import noop from 'lodash/noop';
import rest from './internal/rest';
import onlyOnce from './internal/onlyOnce';
+import wrapAsync from './internal/wrapAsync';
/**
* The post-check version of [`whilst`]{@link module:ControlFlow.whilst}. To reflect the difference in
@@ -15,11 +16,10 @@ import onlyOnce from './internal/onlyOnce';
* @method
* @see [async.whilst]{@link module:ControlFlow.whilst}
* @category Control Flow
- * @param {Function} iteratee - A function which is called each time `test`
- * passes. The function is passed a `callback(err)`, which must be called once
- * it has completed with an optional `err` argument. Invoked with (callback).
+ * @param {AsyncFunction} iteratee - A function which is called each time `test`
+ * passes. Invoked with (callback).
* @param {Function} test - synchronous truth test to perform after each
- * execution of `iteratee`. Invoked with the non-error callback results of
+ * execution of `iteratee`. Invoked with any non-error callback results of
* `iteratee`.
* @param {Function} [callback] - A callback which is called after the test
* function has failed and repeated execution of `iteratee` has stopped.
@@ -28,10 +28,11 @@ import onlyOnce from './internal/onlyOnce';
*/
export default function doWhilst(iteratee, test, callback) {
callback = onlyOnce(callback || noop);
+ var _iteratee = wrapAsync(iteratee);
var next = rest(function(err, args) {
if (err) return callback(err);
- if (test.apply(this, args)) return iteratee(next);
+ if (test.apply(this, args)) return _iteratee(next);
callback.apply(null, [null].concat(args));
});
- iteratee(next);
+ _iteratee(next);
}
diff --git a/lib/during.js b/lib/during.js
index 376c445..ae5a4c1 100644
--- a/lib/during.js
+++ b/lib/during.js
@@ -1,5 +1,6 @@
import noop from 'lodash/noop';
import onlyOnce from './internal/onlyOnce';
+import wrapAsync from './internal/wrapAsync';
/**
* Like [`whilst`]{@link module:ControlFlow.whilst}, except the `test` is an asynchronous function that
@@ -13,11 +14,10 @@ import onlyOnce from './internal/onlyOnce';
* @method
* @see [async.whilst]{@link module:ControlFlow.whilst}
* @category Control Flow
- * @param {Function} test - asynchronous truth test to perform before each
+ * @param {AsyncFunction} test - asynchronous truth test to perform before each
* execution of `fn`. Invoked with (callback).
- * @param {Function} fn - A function which is called each time `test` passes.
- * The function is passed a `callback(err)`, which must be called once it has
- * completed with an optional `err` argument. Invoked with (callback).
+ * @param {AsyncFunction} fn - An async function which is called each time
+ * `test` passes. Invoked with (callback).
* @param {Function} [callback] - A callback which is called after the test
* function has failed and repeated execution of `fn` has stopped. `callback`
* will be passed an error, if one occurred, otherwise `null`.
@@ -40,17 +40,19 @@ import onlyOnce from './internal/onlyOnce';
*/
export default function during(test, fn, callback) {
callback = onlyOnce(callback || noop);
+ var _fn = wrapAsync(fn);
+ var _test = wrapAsync(test);
function next(err) {
if (err) return callback(err);
- test(check);
+ _test(check);
}
function check(err, truth) {
if (err) return callback(err);
if (!truth) return callback(null);
- fn(next);
+ _fn(next);
}
- test(check);
+ _test(check);
}
diff --git a/lib/each.js b/lib/each.js
index 5bf6bd4..29f2baf 100644
--- a/lib/each.js
+++ b/lib/each.js
@@ -1,5 +1,6 @@
import eachOf from './eachOf';
import withoutIndex from './internal/withoutIndex';
+import wrapAsync from './internal/wrapAsync'
/**
* Applies the function `iteratee` to each item in `coll`, in parallel.
@@ -18,12 +19,10 @@ import withoutIndex from './internal/withoutIndex';
* @alias forEach
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A function to apply to each item
- * in `coll`. The iteratee is passed a `callback(err)` which must be called once
- * it has completed. If no error has occurred, the `callback` should be run
- * without arguments or with an explicit `null` argument. The array index is not
- * passed to the iteratee. Invoked with (item, callback). If you need the index,
- * use `eachOf`.
+ * @param {AsyncFunction} iteratee - An async function to apply to
+ * each item in `coll`. Invoked with (item, callback).
+ * The array index is not passed to the iteratee.
+ * If you need the index, use `eachOf`.
* @param {Function} [callback] - A callback which is called when all
* `iteratee` functions have finished, or an error occurs. Invoked with (err).
* @example
@@ -61,5 +60,5 @@ import withoutIndex from './internal/withoutIndex';
* });
*/
export default function eachLimit(coll, iteratee, callback) {
- eachOf(coll, withoutIndex(iteratee), callback);
+ eachOf(coll, withoutIndex(wrapAsync(iteratee)), callback);
}
diff --git a/lib/eachLimit.js b/lib/eachLimit.js
index e2ed790..462e329 100644
--- a/lib/eachLimit.js
+++ b/lib/eachLimit.js
@@ -1,5 +1,6 @@
import eachOfLimit from './internal/eachOfLimit';
import withoutIndex from './internal/withoutIndex';
+import wrapAsync from './internal/wrapAsync';
/**
* The same as [`each`]{@link module:Collections.each} but runs a maximum of `limit` async operations at a time.
@@ -13,15 +14,14 @@ import withoutIndex from './internal/withoutIndex';
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
* @param {number} limit - The maximum number of async operations at a time.
- * @param {Function} iteratee - A function to apply to each item in `coll`. The
- * iteratee is passed a `callback(err)` which must be called once it has
- * completed. If no error has occurred, the `callback` should be run without
- * arguments or with an explicit `null` argument. The array index is not passed
- * to the iteratee. Invoked with (item, callback). If you need the index, use
- * `eachOfLimit`.
+ * @param {AsyncFunction} iteratee - An async function to apply to each item in
+ * `coll`.
+ * The array index is not passed to the iteratee.
+ * If you need the index, use `eachOfLimit`.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called when all
* `iteratee` functions have finished, or an error occurs. Invoked with (err).
*/
export default function eachLimit(coll, limit, iteratee, callback) {
- eachOfLimit(limit)(coll, withoutIndex(iteratee), callback);
+ eachOfLimit(limit)(coll, withoutIndex(wrapAsync(iteratee)), callback);
}
diff --git a/lib/eachOf.js b/lib/eachOf.js
index 798f270..9ab3eb6 100644
--- a/lib/eachOf.js
+++ b/lib/eachOf.js
@@ -6,6 +6,7 @@ import doLimit from './internal/doLimit';
import noop from 'lodash/noop';
import once from './internal/once';
import onlyOnce from './internal/onlyOnce';
+import wrapAsync from './internal/wrapAsync';
// eachOf implementation optimized for array-likes
function eachOfArrayLike(coll, iteratee, callback) {
@@ -45,12 +46,10 @@ var eachOfGeneric = doLimit(eachOfLimit, Infinity);
* @category Collection
* @see [async.each]{@link module:Collections.each}
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A function to apply to each
- * item in `coll`. The `key` is the item's key, or index in the case of an
- * array. The iteratee is passed a `callback(err)` which must be called once it
- * has completed. If no error has occurred, the callback should be run without
- * arguments or with an explicit `null` argument. Invoked with
- * (item, key, callback).
+ * @param {AsyncFunction} iteratee - A function to apply to each
+ * item in `coll`.
+ * The `key` is the item's key, or index in the case of an array.
+ * Invoked with (item, key, callback).
* @param {Function} [callback] - A callback which is called when all
* `iteratee` functions have finished, or an error occurs. Invoked with (err).
* @example
@@ -76,5 +75,5 @@ var eachOfGeneric = doLimit(eachOfLimit, Infinity);
*/
export default function(coll, iteratee, callback) {
var eachOfImplementation = isArrayLike(coll) ? eachOfArrayLike : eachOfGeneric;
- eachOfImplementation(coll, iteratee, callback);
+ eachOfImplementation(coll, wrapAsync(iteratee), callback);
}
diff --git a/lib/eachOfLimit.js b/lib/eachOfLimit.js
index c3b4567..1de28ef 100644
--- a/lib/eachOfLimit.js
+++ b/lib/eachOfLimit.js
@@ -1,4 +1,5 @@
import _eachOfLimit from './internal/eachOfLimit';
+import wrapAsync from './internal/wrapAsync';
/**
* The same as [`eachOf`]{@link module:Collections.eachOf} but runs a maximum of `limit` async operations at a
@@ -13,15 +14,13 @@ import _eachOfLimit from './internal/eachOfLimit';
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
* @param {number} limit - The maximum number of async operations at a time.
- * @param {Function} iteratee - A function to apply to each
+ * @param {AsyncFunction} iteratee - An async function to apply to each
* item in `coll`. The `key` is the item's key, or index in the case of an
- * array. The iteratee is passed a `callback(err)` which must be called once it
- * has completed. If no error has occurred, the callback should be run without
- * arguments or with an explicit `null` argument. Invoked with
- * (item, key, callback).
+ * array.
+ * Invoked with (item, key, callback).
* @param {Function} [callback] - A callback which is called when all
* `iteratee` functions have finished, or an error occurs. Invoked with (err).
*/
export default function eachOfLimit(coll, limit, iteratee, callback) {
- _eachOfLimit(limit)(coll, iteratee, callback);
+ _eachOfLimit(limit)(coll, wrapAsync(iteratee), callback);
}
diff --git a/lib/eachOfSeries.js b/lib/eachOfSeries.js
index 21e816d..fc1a097 100644
--- a/lib/eachOfSeries.js
+++ b/lib/eachOfSeries.js
@@ -12,11 +12,9 @@ import doLimit from './internal/doLimit';
* @alias forEachOfSeries
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A function to apply to each item in `coll`. The
- * `key` is the item's key, or index in the case of an array. The iteratee is
- * passed a `callback(err)` which must be called once it has completed. If no
- * error has occurred, the callback should be run without arguments or with an
- * explicit `null` argument. Invoked with (item, key, callback).
+ * @param {AsyncFunction} iteratee - An async function to apply to each item in
+ * `coll`.
+ * Invoked with (item, key, callback).
* @param {Function} [callback] - A callback which is called when all `iteratee`
* functions have finished, or an error occurs. Invoked with (err).
*/
diff --git a/lib/eachSeries.js b/lib/eachSeries.js
index 0839d8c..9f8d7de 100644
--- a/lib/eachSeries.js
+++ b/lib/eachSeries.js
@@ -12,12 +12,11 @@ import doLimit from './internal/doLimit';
* @alias forEachSeries
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A function to apply to each
- * item in `coll`. The iteratee is passed a `callback(err)` which must be called
- * once it has completed. If no error has occurred, the `callback` should be run
- * without arguments or with an explicit `null` argument. The array index is
- * not passed to the iteratee. Invoked with (item, callback). If you need the
- * index, use `eachOfSeries`.
+ * @param {AsyncFunction} iteratee - An async function to apply to each
+ * item in `coll`.
+ * The array index is not passed to the iteratee.
+ * If you need the index, use `eachOfSeries`.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called when all
* `iteratee` functions have finished, or an error occurs. Invoked with (err).
*/
diff --git a/lib/ensureAsync.js b/lib/ensureAsync.js
index c60d07e..a579efc 100644
--- a/lib/ensureAsync.js
+++ b/lib/ensureAsync.js
@@ -1,5 +1,6 @@
import setImmediate from './internal/setImmediate';
import initialParams from './internal/initialParams';
+import { isAsync } from './internal/wrapAsync';
/**
* Wrap an async function and ensure it calls its callback on a later tick of
@@ -7,16 +8,17 @@ import initialParams from './internal/initialParams';
* no extra deferral is added. This is useful for preventing stack overflows
* (`RangeError: Maximum call stack size exceeded`) and generally keeping
* [Zalgo](http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony)
- * contained.
+ * contained. ES2017 `async` functions are returned as-is -- they are immune
+ * to Zalgo's corrupting influences, as they always resolve on a later tick.
*
* @name ensureAsync
* @static
* @memberOf module:Utils
* @method
* @category Util
- * @param {Function} fn - an async function, one that expects a node-style
+ * @param {AsyncFunction} fn - an async function, one that expects a node-style
* callback as its last argument.
- * @returns {Function} Returns a wrapped function with the exact same call
+ * @returns {AsyncFunction} Returns a wrapped function with the exact same call
* signature as the function passed in.
* @example
*
@@ -36,6 +38,7 @@ import initialParams from './internal/initialParams';
* async.mapSeries(args, async.ensureAsync(sometimesAsync), done);
*/
export default function ensureAsync(fn) {
+ if (isAsync(fn)) return fn;
return initialParams(function (args, callback) {
var sync = true;
args.push(function () {
diff --git a/lib/every.js b/lib/every.js
index b34ad1f..eb10748 100644
--- a/lib/every.js
+++ b/lib/every.js
@@ -13,10 +13,10 @@ import notId from './internal/notId';
* @alias all
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A truth test to apply to each item in the
- * collection in parallel. The iteratee is passed a `callback(err, truthValue)`
- * which must be called with a boolean argument once it has completed. Invoked
- * with (item, callback).
+ * @param {AsyncFunction} iteratee - An async truth test to apply to each item
+ * in the collection in parallel.
+ * The iteratee must complete with a boolean result value.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called after all the
* `iteratee` functions have finished. Result will be either `true` or `false`
* depending on the values of the async tests. Invoked with (err, result).
diff --git a/lib/everyLimit.js b/lib/everyLimit.js
index 4cc7091..89a69fc 100644
--- a/lib/everyLimit.js
+++ b/lib/everyLimit.js
@@ -14,10 +14,10 @@ import notId from './internal/notId';
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
* @param {number} limit - The maximum number of async operations at a time.
- * @param {Function} iteratee - A truth test to apply to each item in the
- * collection in parallel. The iteratee is passed a `callback(err, truthValue)`
- * which must be called with a boolean argument once it has completed. Invoked
- * with (item, callback).
+ * @param {AsyncFunction} iteratee - An async truth test to apply to each item
+ * in the collection in parallel.
+ * The iteratee must complete with a boolean result value.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called after all the
* `iteratee` functions have finished. Result will be either `true` or `false`
* depending on the values of the async tests. Invoked with (err, result).
diff --git a/lib/everySeries.js b/lib/everySeries.js
index 7434748..b67368c 100644
--- a/lib/everySeries.js
+++ b/lib/everySeries.js
@@ -12,10 +12,10 @@ import doLimit from './internal/doLimit';
* @alias allSeries
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A truth test to apply to each item in the
- * collection in parallel. The iteratee is passed a `callback(err, truthValue)`
- * which must be called with a boolean argument once it has completed. Invoked
- * with (item, callback).
+ * @param {AsyncFunction} iteratee - An async truth test to apply to each item
+ * in the collection in series.
+ * The iteratee must complete with a boolean result value.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called after all the
* `iteratee` functions have finished. Result will be either `true` or `false`
* depending on the values of the async tests. Invoked with (err, result).
diff --git a/lib/forever.js b/lib/forever.js
index 0147395..f7be0b2 100644
--- a/lib/forever.js
+++ b/lib/forever.js
@@ -2,21 +2,22 @@ import noop from 'lodash/noop';
import onlyOnce from './internal/onlyOnce';
import ensureAsync from './ensureAsync';
+import wrapAsync from './internal/wrapAsync';
/**
* Calls the asynchronous function `fn` with a callback parameter that allows it
* to call itself again, in series, indefinitely.
- * If an error is passed to the
- * callback then `errback` is called with the error, and execution stops,
- * otherwise it will never be called.
+ * If an error is passed to the callback then `errback` is called with the
+ * error, and execution stops, otherwise it will never be called.
*
* @name forever
* @static
* @memberOf module:ControlFlow
* @method
* @category Control Flow
- * @param {Function} fn - a function to call repeatedly. Invoked with (next).
+ * @param {AsyncFunction} fn - an async function to call repeatedly.
+ * Invoked with (next).
* @param {Function} [errback] - when `fn` passes an error to it's callback,
* this function will be called, and execution stops. Invoked with (err).
* @example
@@ -34,7 +35,7 @@ import ensureAsync from './ensureAsync';
*/
export default function forever(fn, errback) {
var done = onlyOnce(errback || noop);
- var task = ensureAsync(fn);
+ var task = wrapAsync(ensureAsync(fn));
function next(err) {
if (err) return done(err);
diff --git a/lib/groupBy.js b/lib/groupBy.js
index 31e2c0b..a2f923f 100644
--- a/lib/groupBy.js
+++ b/lib/groupBy.js
@@ -18,10 +18,10 @@ import groupByLimit from './groupByLimit';
* @method
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A function to apply to each item in `coll`.
- * The iteratee is passed a `callback(err, key)` which must be called once it
- * has completed with an error (which can be `null`) and the `key` to group the
- * value under. Invoked with (value, callback).
+ * @param {AsyncFunction} iteratee - An async function to apply to each item in
+ * `coll`.
+ * The iteratee should complete with a `key` to group the value under.
+ * Invoked with (value, callback).
* @param {Function} [callback] - A callback which is called when all `iteratee`
* functions have finished, or an error occurs. Result is an `Object` whoses
* properties are arrays of values which returned the corresponding key.
diff --git a/lib/groupByLimit.js b/lib/groupByLimit.js
index 9fc71a0..b0a5ef3 100644
--- a/lib/groupByLimit.js
+++ b/lib/groupByLimit.js
@@ -1,6 +1,6 @@
import noop from 'lodash/noop';
import mapLimit from './mapLimit';
-
+import wrapAsync from './internal/wrapAsync';
/**
* The same as [`groupBy`]{@link module:Collections.groupBy} but runs a maximum of `limit` async operations at a time.
*
@@ -12,19 +12,19 @@ import mapLimit from './mapLimit';
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
* @param {number} limit - The maximum number of async operations at a time.
- * @param {Function} iteratee - A function to apply to each item in `coll`.
- * The iteratee is passed a `callback(err, key)` which must be called once it
- * has completed with an error (which can be `null`) and the `key` to group the
- * value under. Invoked with (value, callback).
+ * @param {AsyncFunction} iteratee - An async function to apply to each item in
+ * `coll`.
+ * The iteratee should complete with a `key` to group the value under.
+ * Invoked with (value, callback).
* @param {Function} [callback] - A callback which is called when all `iteratee`
* functions have finished, or an error occurs. Result is an `Object` whoses
* properties are arrays of values which returned the corresponding key.
*/
export default function(coll, limit, iteratee, callback) {
callback = callback || noop;
-
+ var _iteratee = wrapAsync(iteratee);
mapLimit(coll, limit, function(val, callback) {
- iteratee(val, function(err, key) {
+ _iteratee(val, function(err, key) {
if (err) return callback(err);
return callback(null, {key: key, val: val});
});
diff --git a/lib/groupBySeries.js b/lib/groupBySeries.js
index 5df9a3c..91935c3 100644
--- a/lib/groupBySeries.js
+++ b/lib/groupBySeries.js
@@ -12,10 +12,10 @@ import groupByLimit from './groupByLimit';
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
* @param {number} limit - The maximum number of async operations at a time.
- * @param {Function} iteratee - A function to apply to each item in `coll`.
- * The iteratee is passed a `callback(err, key)` which must be called once it
- * has completed with an error (which can be `null`) and the `key` to group the
- * value under. Invoked with (value, callback).
+ * @param {AsyncFunction} iteratee - An async function to apply to each item in
+ * `coll`.
+ * The iteratee should complete with a `key` to group the value under.
+ * Invoked with (value, callback).
* @param {Function} [callback] - A callback which is called when all `iteratee`
* functions have finished, or an error occurs. Result is an `Object` whoses
* properties are arrays of values which returned the corresponding key.
diff --git a/lib/index.js b/lib/index.js
index 0bb7efe..f1e8e98 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -1,11 +1,52 @@
/**
+ * An "async function" in the context of Async is an asynchronous function with
+ * a variable number of parameters, with the final parameter being a callback.
+ * (`function (arg1, arg2, ..., callback) {}`)
+ * The final callback is of the form `callback(err, results...)`, which must be
+ * called once the function is completed. The callback should be called with a
+ * Error as its first argument to signal that an error occurred.
+ * Otherwise, if no error occurred, it should be called with `null` as the first
+ * argument, and any additional `result` arguments that may apply, to signal
+ * successful completion.
+ * The callback must be called exactly once, ideally on a later tick of the
+ * JavaScript event loop.
+ *
+ * This type of function is also referred to as a "Node-style async function",
+ * or a "continuation passing-style function" (CPS). Most of the methods of this
+ * library are themselves CPS/Node-style async functions, or functions that
+ * return CPS/Node-style async functions.
+ *
+ * Wherever we accept a Node-style async function, we also directly accept an
+ * [ES2017 `async` function]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function}.
+ * In this case, the `async` function will not be passed a final callback
+ * argument, and any thrown error will be used as the `err` argument of the
+ * implicit callback, and the return value will be used as the `result` value.
+ * (i.e. a `rejected` of the returned Promise becomes the `err` callback
+ * argument, and a `resolved` value becomes the `result`.)
+ *
+ * Note, due to JavaScript limitations, we can only detect native `async`
+ * functions and not transpilied implementations.
+ * Your environment must have `async`/`await` support for this to work.
+ * (e.g. Node > v7.6, or a recent version of a modern browser).
+ * If you are using `async` functions through a transpiler (e.g. Babel), you
+ * must still wrap the function with [asyncify]{@link module:Utils.asyncify},
+ * because the `async function` will be compiled to an ordinary function that
+ * returns a promise.
+ *
+ * @typedef {Function} AsyncFunction
+ * @static
+ */
+
+/**
* Async is a utility module which provides straight-forward, powerful functions
* for working with asynchronous JavaScript. Although originally designed for
* use with [Node.js](http://nodejs.org) and installable via
* `npm install --save async`, it can also be used directly in the browser.
* @module async
+ * @see AsyncFunction
*/
+
/**
* A collection of `async` functions for manipulating collections, such as
* arrays and objects.
@@ -17,10 +58,11 @@
* @module ControlFlow
*/
- /**
- * A collection of `async` utility functions.
- * @module Utils
- */
+/**
+ * A collection of `async` utility functions.
+ * @module Utils
+ */
+
import applyEach from './applyEach';
import applyEachSeries from './applyEachSeries';
import apply from './apply';
diff --git a/lib/internal/applyEach.js b/lib/internal/applyEach.js
index aca2b7d..285a6a2 100644
--- a/lib/internal/applyEach.js
+++ b/lib/internal/applyEach.js
@@ -1,12 +1,13 @@
import rest from './rest';
import initialParams from './initialParams';
+import wrapAsync from './wrapAsync';
export default function applyEach(eachfn) {
return rest(function(fns, args) {
var go = initialParams(function(args, callback) {
var that = this;
return eachfn(fns, function (fn, cb) {
- fn.apply(that, args.concat(cb));
+ wrapAsync(fn).apply(that, args.concat(cb));
}, callback);
});
if (args.length) {
diff --git a/lib/internal/consoleFunc.js b/lib/internal/consoleFunc.js
index 6ab2f7b..35374d7 100644
--- a/lib/internal/consoleFunc.js
+++ b/lib/internal/consoleFunc.js
@@ -1,9 +1,10 @@
import arrayEach from 'lodash/_arrayEach';
import rest from './rest';
+import wrapAsync from './wrapAsync';
export default function consoleFunc(name) {
return rest(function (fn, args) {
- fn.apply(null, args.concat(rest(function (err, args) {
+ wrapAsync(fn).apply(null, args.concat(rest(function (err, args) {
if (typeof console === 'object') {
if (err) {
if (console.error) {
diff --git a/lib/internal/doParallel.js b/lib/internal/doParallel.js
index d436208..deed912 100644
--- a/lib/internal/doParallel.js
+++ b/lib/internal/doParallel.js
@@ -1,7 +1,8 @@
import eachOf from '../eachOf';
+import wrapAsync from './wrapAsync';
export default function doParallel(fn) {
return function (obj, iteratee, callback) {
- return fn(eachOf, obj, iteratee, callback);
+ return fn(eachOf, obj, wrapAsync(iteratee), callback);
};
}
diff --git a/lib/internal/doParallelLimit.js b/lib/internal/doParallelLimit.js
index b29da51..6d0f607 100644
--- a/lib/internal/doParallelLimit.js
+++ b/lib/internal/doParallelLimit.js
@@ -1,7 +1,8 @@
import eachOfLimit from './eachOfLimit';
+import wrapAsync from './wrapAsync';
export default function doParallelLimit(fn) {
return function (obj, limit, iteratee, callback) {
- return fn(eachOfLimit(limit), obj, iteratee, callback);
+ return fn(eachOfLimit(limit), obj, wrapAsync(iteratee), callback);
};
}
diff --git a/lib/internal/doSeries.js b/lib/internal/doSeries.js
index 96e21ca..9fea488 100644
--- a/lib/internal/doSeries.js
+++ b/lib/internal/doSeries.js
@@ -1,7 +1,8 @@
import eachOfSeries from '../eachOfSeries';
+import wrapAsync from './wrapAsync';
export default function doSeries(fn) {
return function (obj, iteratee, callback) {
- return fn(eachOfSeries, obj, iteratee, callback);
+ return fn(eachOfSeries, obj, wrapAsync(iteratee), callback);
};
}
diff --git a/lib/internal/filter.js b/lib/internal/filter.js
index 5af788c..032bd33 100644
--- a/lib/internal/filter.js
+++ b/lib/internal/filter.js
@@ -3,6 +3,8 @@ import isArrayLike from 'lodash/isArrayLike';
import property from 'lodash/_baseProperty';
import noop from 'lodash/noop';
+import wrapAsync from './wrapAsync';
+
function filterArray(eachfn, arr, iteratee, callback) {
var truthValues = new Array(arr.length);
eachfn(arr, function (x, index, callback) {
@@ -46,5 +48,5 @@ function filterGeneric(eachfn, coll, iteratee, callback) {
export default function _filter(eachfn, coll, iteratee, callback) {
var filter = isArrayLike(coll) ? filterArray : filterGeneric;
- filter(eachfn, coll, iteratee, callback || noop);
+ filter(eachfn, coll, wrapAsync(iteratee), callback || noop);
}
diff --git a/lib/internal/map.js b/lib/internal/map.js
index 453cd29..9cd927e 100644
--- a/lib/internal/map.js
+++ b/lib/internal/map.js
@@ -1,14 +1,16 @@
import noop from 'lodash/noop';
+import wrapAsync from './wrapAsync';
export default function _asyncMap(eachfn, arr, iteratee, callback) {
callback = callback || noop;
arr = arr || [];
var results = [];
var counter = 0;
+ var _iteratee = wrapAsync(iteratee);
eachfn(arr, function (value, _, callback) {
var index = counter++;
- iteratee(value, function (err, v) {
+ _iteratee(value, function (err, v) {
results[index] = v;
callback(err);
});
diff --git a/lib/internal/parallel.js b/lib/internal/parallel.js
index d7c5cd9..70993d3 100644
--- a/lib/internal/parallel.js
+++ b/lib/internal/parallel.js
@@ -1,13 +1,14 @@
import noop from 'lodash/noop';
import isArrayLike from 'lodash/isArrayLike';
import rest from './rest';
+import wrapAsync from './wrapAsync';
export default function _parallel(eachfn, tasks, callback) {
callback = callback || noop;
var results = isArrayLike(tasks) ? [] : {};
eachfn(tasks, function (task, key, callback) {
- task(rest(function (err, args) {
+ wrapAsync(task)(rest(function (err, args) {
if (args.length <= 1) {
args = args[0];
}
diff --git a/lib/internal/queue.js b/lib/internal/queue.js
index 7a438da..c825e62 100644
--- a/lib/internal/queue.js
+++ b/lib/internal/queue.js
@@ -6,6 +6,7 @@ import rest from './rest';
import onlyOnce from './onlyOnce';
import setImmediate from './setImmediate';
import DLL from './DoublyLinkedList';
+import wrapAsync from './wrapAsync';
export default function queue(worker, concurrency, payload) {
if (concurrency == null) {
@@ -15,6 +16,10 @@ export default function queue(worker, concurrency, payload) {
throw new Error('Concurrency must not be zero');
}
+ var _worker = wrapAsync(worker);
+ var numRunning = 0;
+ var workersList = [];
+
function _insert(data, insertAtFront, callback) {
if (callback != null && typeof callback !== 'function') {
throw new Error('task callback must be a function');
@@ -47,7 +52,7 @@ export default function queue(worker, concurrency, payload) {
function _next(tasks) {
return rest(function(args){
- workers -= 1;
+ numRunning -= 1;
for (var i = 0, l = tasks.length; i < l; i++) {
var task = tasks[i];
@@ -63,7 +68,7 @@ export default function queue(worker, concurrency, payload) {
}
}
- if (workers <= (q.concurrency - q.buffer) ) {
+ if (numRunning <= (q.concurrency - q.buffer) ) {
q.unsaturated();
}
@@ -74,8 +79,6 @@ export default function queue(worker, concurrency, payload) {
});
}
- var workers = 0;
- var workersList = [];
var isProcessing = false;
var q = {
_tasks: new DLL(),
@@ -106,7 +109,7 @@ export default function queue(worker, concurrency, payload) {
return;
}
isProcessing = true;
- while(!q.paused && workers < q.concurrency && q._tasks.length){
+ while(!q.paused && numRunning < q.concurrency && q._tasks.length){
var tasks = [], data = [];
var l = q._tasks.length;
if (q.payload) l = Math.min(l, q.payload);
@@ -119,15 +122,15 @@ export default function queue(worker, concurrency, payload) {
if (q._tasks.length === 0) {
q.empty();
}
- workers += 1;
+ numRunning += 1;
workersList.push(tasks[0]);
- if (workers === q.concurrency) {
+ if (numRunning === q.concurrency) {
q.saturated();
}
var cb = onlyOnce(_next(tasks));
- worker(data, cb);
+ _worker(data, cb);
}
isProcessing = false;
},
@@ -135,13 +138,13 @@ export default function queue(worker, concurrency, payload) {
return q._tasks.length;
},
running: function () {
- return workers;
+ return numRunning;
},
workersList: function () {
return workersList;
},
idle: function() {
- return q._tasks.length + workers === 0;
+ return q._tasks.length + numRunning === 0;
},
pause: function () {
q.paused = true;
diff --git a/lib/internal/wrapAsync.js b/lib/internal/wrapAsync.js
new file mode 100644
index 0000000..aee0275
--- /dev/null
+++ b/lib/internal/wrapAsync.js
@@ -0,0 +1,27 @@
+import identity from 'lodash/identity';
+import asyncify from '../asyncify';
+
+var supportsSymbol = typeof Symbol === 'function';
+
+function supportsAsync() {
+ var supported;
+ try {
+ /* eslint no-eval: 0 */
+ supported = isAsync(eval('(async function () {})'));
+ } catch (e) {
+ supported = false;
+ }
+ return supported;
+}
+
+function isAsync(fn) {
+ return supportsSymbol && fn[Symbol.toStringTag] === 'AsyncFunction';
+}
+
+function wrapAsync(asyncFn) {
+ return isAsync(asyncFn) ? asyncify(asyncFn) : asyncFn;
+}
+
+export default supportsAsync() ? wrapAsync : identity;
+
+export { supportsAsync, isAsync };
diff --git a/lib/log.js b/lib/log.js
index 848661d..c39e033 100644
--- a/lib/log.js
+++ b/lib/log.js
@@ -11,8 +11,8 @@ import consoleFunc from './internal/consoleFunc';
* @memberOf module:Utils
* @method
* @category Util
- * @param {Function} function - The function you want to eventually apply all
- * arguments to.
+ * @param {AsyncFunction} function - The function you want to eventually apply
+ * all arguments to.
* @param {...*} arguments... - Any number of arguments to apply to the function.
* @example
*
diff --git a/lib/map.js b/lib/map.js
index 76d6058..100ab7a 100644
--- a/lib/map.js
+++ b/lib/map.js
@@ -24,10 +24,10 @@ import map from './internal/map';
* @method
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A function to apply to each item in `coll`.
- * The iteratee is passed a `callback(err, transformed)` which must be called
- * once it has completed with an error (which can be `null`) and a
- * transformed item. Invoked with (item, callback).
+ * @param {AsyncFunction} iteratee - An async function to apply to each item in
+ * `coll`.
+ * The iteratee should complete with the transformed item.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called when all `iteratee`
* functions have finished, or an error occurs. Results is an Array of the
* transformed items from the `coll`. Invoked with (err, results).
diff --git a/lib/mapLimit.js b/lib/mapLimit.js
index a54922d..0a2fc02 100644
--- a/lib/mapLimit.js
+++ b/lib/mapLimit.js
@@ -12,10 +12,10 @@ import map from './internal/map';
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
* @param {number} limit - The maximum number of async operations at a time.
- * @param {Function} iteratee - A function to apply to each item in `coll`.
- * The iteratee is passed a `callback(err, transformed)` which must be called
- * once it has completed with an error (which can be `null`) and a transformed
- * item. Invoked with (item, callback).
+ * @param {AsyncFunction} iteratee - An async function to apply to each item in
+ * `coll`.
+ * The iteratee should complete with the transformed item.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called when all `iteratee`
* functions have finished, or an error occurs. Results is an array of the
* transformed items from the `coll`. Invoked with (err, results).
diff --git a/lib/mapSeries.js b/lib/mapSeries.js
index e1f3d0d..596c75e 100644
--- a/lib/mapSeries.js
+++ b/lib/mapSeries.js
@@ -11,10 +11,10 @@ import doLimit from './internal/doLimit';
* @see [async.map]{@link module:Collections.map}
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A function to apply to each item in `coll`.
- * The iteratee is passed a `callback(err, transformed)` which must be called
- * once it has completed with an error (which can be `null`) and a
- * transformed item. Invoked with (item, callback).
+ * @param {AsyncFunction} iteratee - An async function to apply to each item in
+ * `coll`.
+ * The iteratee should complete with the transformed item.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called when all `iteratee`
* functions have finished, or an error occurs. Results is an array of the
* transformed items from the `coll`. Invoked with (err, results).
diff --git a/lib/mapValues.js b/lib/mapValues.js
index afc43f4..d6a4ad2 100644
--- a/lib/mapValues.js
+++ b/lib/mapValues.js
@@ -21,10 +21,10 @@ import doLimit from './internal/doLimit';
* @method
* @category Collection
* @param {Object} obj - A collection to iterate over.
- * @param {Function} iteratee - A function to apply to each value and key in
- * `coll`. The iteratee is passed a `callback(err, transformed)` which must be
- * called once it has completed with an error (which can be `null`) and a
- * transformed value. Invoked with (value, key, callback).
+ * @param {AsyncFunction} iteratee - A function to apply to each value and key
+ * in `coll`.
+ * The iteratee should complete with the transformed value as its result.
+ * Invoked with (value, key, callback).
* @param {Function} [callback] - A callback which is called when all `iteratee`
* functions have finished, or an error occurs. `result` is a new object consisting
* of each key from `obj`, with each transformed value on the right-hand side.
diff --git a/lib/mapValuesLimit.js b/lib/mapValuesLimit.js
index 6c9fe06..c6e020d 100644
--- a/lib/mapValuesLimit.js
+++ b/lib/mapValuesLimit.js
@@ -2,6 +2,7 @@ import eachOfLimit from './eachOfLimit';
import noop from 'lodash/noop';
import once from './internal/once';
+import wrapAsync from './internal/wrapAsync';
/**
* The same as [`mapValues`]{@link module:Collections.mapValues} but runs a maximum of `limit` async operations at a
@@ -15,10 +16,10 @@ import once from './internal/once';
* @category Collection
* @param {Object} obj - A collection to iterate over.
* @param {number} limit - The maximum number of async operations at a time.
- * @param {Function} iteratee - A function to apply to each value in `obj`.
- * The iteratee is passed a `callback(err, transformed)` which must be called
- * once it has completed with an error (which can be `null`) and a
- * transformed value. Invoked with (value, key, callback).
+ * @param {AsyncFunction} iteratee - A function to apply to each value and key
+ * in `coll`.
+ * The iteratee should complete with the transformed value as its result.
+ * Invoked with (value, key, callback).
* @param {Function} [callback] - A callback which is called when all `iteratee`
* functions have finished, or an error occurs. `result` is a new object consisting
* of each key from `obj`, with each transformed value on the right-hand side.
@@ -27,8 +28,9 @@ import once from './internal/once';
export default function mapValuesLimit(obj, limit, iteratee, callback) {
callback = once(callback || noop);
var newObj = {};
+ var _iteratee = wrapAsync(iteratee)
eachOfLimit(obj, limit, function(val, key, next) {
- iteratee(val, key, function (err, result) {
+ _iteratee(val, key, function (err, result) {
if (err) return next(err);
newObj[key] = result;
next();
diff --git a/lib/mapValuesSeries.js b/lib/mapValuesSeries.js
index c1530c2..ab0b8f8 100644
--- a/lib/mapValuesSeries.js
+++ b/lib/mapValuesSeries.js
@@ -11,10 +11,10 @@ import doLimit from './internal/doLimit';
* @see [async.mapValues]{@link module:Collections.mapValues}
* @category Collection
* @param {Object} obj - A collection to iterate over.
- * @param {Function} iteratee - A function to apply to each value in `obj`.
- * The iteratee is passed a `callback(err, transformed)` which must be called
- * once it has completed with an error (which can be `null`) and a
- * transformed value. Invoked with (value, key, callback).
+ * @param {AsyncFunction} iteratee - A function to apply to each value and key
+ * in `coll`.
+ * The iteratee should complete with the transformed value as its result.
+ * Invoked with (value, key, callback).
* @param {Function} [callback] - A callback which is called when all `iteratee`
* functions have finished, or an error occurs. `result` is a new object consisting
* of each key from `obj`, with each transformed value on the right-hand side.
diff --git a/lib/memoize.js b/lib/memoize.js
index ec83620..de71c33 100644
--- a/lib/memoize.js
+++ b/lib/memoize.js
@@ -3,13 +3,14 @@ import rest from './internal/rest';
import setImmediate from './internal/setImmediate';
import initialParams from './internal/initialParams';
+import wrapAsync from './internal/wrapAsync';
function has(obj, key) {
return key in obj;
}
/**
- * Caches the results of an `async` function. When creating a hash to store
+ * Caches the results of an async function. When creating a hash to store
* function results against, the callback is omitted from the hash and an
* optional hash function can be used.
*
@@ -27,11 +28,11 @@ function has(obj, key) {
* @memberOf module:Utils
* @method
* @category Util
- * @param {Function} fn - The function to proxy and cache results from.
+ * @param {AsyncFunction} fn - The async function to proxy and cache results from.
* @param {Function} hasher - An optional function for generating a custom hash
* for storing results. It has all the arguments applied to it apart from the
* callback, and must be synchronous.
- * @returns {Function} a memoized version of `fn`
+ * @returns {AsyncFunction} a memoized version of `fn`
* @example
*
* var slow_fn = function(name, callback) {
@@ -49,6 +50,7 @@ export default function memoize(fn, hasher) {
var memo = Object.create(null);
var queues = Object.create(null);
hasher = hasher || identity;
+ var _fn = wrapAsync(fn);
var memoized = initialParams(function memoized(args, callback) {
var key = hasher.apply(null, args);
if (has(memo, key)) {
@@ -59,7 +61,7 @@ export default function memoize(fn, hasher) {
queues[key].push(callback);
} else {
queues[key] = [callback];
- fn.apply(null, args.concat(rest(function(args) {
+ _fn.apply(null, args.concat(rest(function(args) {
memo[key] = args;
var q = queues[key];
delete queues[key];
diff --git a/lib/parallel.js b/lib/parallel.js
index 19d5558..8b6c2ce 100644
--- a/lib/parallel.js
+++ b/lib/parallel.js
@@ -13,6 +13,7 @@ import parallel from './internal/parallel';
* any I/O, they will actually be executed in series. Any synchronous setup
* sections for each task will happen one after the other. JavaScript remains
* single-threaded.
+ *
* **Hint:** Use [`reflect`]{@link module:Utils.reflect} to continue the
* execution of other tasks when a task fails.
*
@@ -26,14 +27,14 @@ import parallel from './internal/parallel';
* @memberOf module:ControlFlow
* @method
* @category Control Flow
- * @param {Array|Iterable|Object} tasks - A collection containing functions to run.
- * Each function is passed a `callback(err, result)` which it must call on
- * completion with an error `err` (which can be `null`) and an optional `result`
- * value.
+ * @param {Array|Iterable|Object} tasks - A collection of
+ * [async functions]{@link AsyncFunction} to run.
+ * Each async function can complete with any number of optional `result` values.
* @param {Function} [callback] - An optional callback to run once all the
* functions have completed successfully. This function gets a results array
* (or object) containing all the result arguments passed to the task callbacks.
* Invoked with (err, results).
+ *
* @example
* async.parallel([
* function(callback) {
diff --git a/lib/parallelLimit.js b/lib/parallelLimit.js
index 926fa85..14e9e52 100644
--- a/lib/parallelLimit.js
+++ b/lib/parallelLimit.js
@@ -11,10 +11,9 @@ import parallel from './internal/parallel';
* @method
* @see [async.parallel]{@link module:ControlFlow.parallel}
* @category Control Flow
- * @param {Array|Collection} tasks - A collection containing functions to run.
- * Each function is passed a `callback(err, result)` which it must call on
- * completion with an error `err` (which can be `null`) and an optional `result`
- * value.
+ * @param {Array|Iterable|Object} tasks - A collection of
+ * [async functions]{@link AsyncFunction} to run.
+ * Each async function can complete with any number of optional `result` values.
* @param {number} limit - The maximum number of async operations at a time.
* @param {Function} [callback] - An optional callback to run once all the
* functions have completed successfully. This function gets a results array
diff --git a/lib/priorityQueue.js b/lib/priorityQueue.js
index 0af0157..aff7293 100644
--- a/lib/priorityQueue.js
+++ b/lib/priorityQueue.js
@@ -15,11 +15,10 @@ import queue from './queue';
* @method
* @see [async.queue]{@link module:ControlFlow.queue}
* @category Control Flow
- * @param {Function} worker - An asynchronous function for processing a queued
- * task, which must call its `callback(err)` argument when finished, with an
- * optional `error` as an argument. If you want to handle errors from an
- * individual task, pass a callback to `q.push()`. Invoked with
- * (task, callback).
+ * @param {AsyncFunction} worker - An async function for processing a queued task.
+ * If you want to handle errors from an individual task, pass a callback to
+ * `q.push()`.
+ * Invoked with (task, callback).
* @param {number} concurrency - An `integer` for determining how many `worker`
* functions should be run in parallel. If omitted, the concurrency defaults to
* `1`. If the concurrency is `0`, an error is thrown.
diff --git a/lib/queue.js b/lib/queue.js
index 5666843..906467c 100644
--- a/lib/queue.js
+++ b/lib/queue.js
@@ -1,4 +1,5 @@
import queue from './internal/queue';
+import wrapAsync from './internal/wrapAsync';
/**
* A queue of tasks for the worker function to complete.
@@ -58,11 +59,9 @@ import queue from './internal/queue';
* @memberOf module:ControlFlow
* @method
* @category Control Flow
- * @param {Function} worker - An asynchronous function for processing a queued
- * task, which must call its `callback(err)` argument when finished, with an
- * optional `error` as an argument. If you want to handle errors from an
- * individual task, pass a callback to `q.push()`. Invoked with
- * (task, callback).
+ * @param {AsyncFunction} worker - An async function for processing a queued task.
+ * If you want to handle errors from an individual task, pass a callback to
+ * `q.push()`. Invoked with (task, callback).
* @param {number} [concurrency=1] - An `integer` for determining how many
* `worker` functions should be run in parallel. If omitted, the concurrency
* defaults to `1`. If the concurrency is `0`, an error is thrown.
@@ -101,7 +100,8 @@ import queue from './internal/queue';
* });
*/
export default function (worker, concurrency) {
+ var _worker = wrapAsync(worker);
return queue(function (items, cb) {
- worker(items[0], cb);
+ _worker(items[0], cb);
}, concurrency, 1);
}
diff --git a/lib/race.js b/lib/race.js
index 5547c86..9b4d6c3 100644
--- a/lib/race.js
+++ b/lib/race.js
@@ -1,6 +1,7 @@
import isArray from 'lodash/isArray';
import noop from 'lodash/noop';
import once from './internal/once';
+import wrapAsync from './internal/wrapAsync';
/**
* Runs the `tasks` array of functions in parallel, without waiting until the
@@ -13,9 +14,8 @@ import once from './internal/once';
* @memberOf module:ControlFlow
* @method
* @category Control Flow
- * @param {Array} tasks - An array containing functions to run. Each function
- * is passed a `callback(err, result)` which it must call on completion with an
- * error `err` (which can be `null`) and an optional `result` value.
+ * @param {Array} tasks - An array containing [async functions]{@link AsyncFunction}
+ * to run. Each function can complete with an optional `result` value.
* @param {Function} callback - A callback to run once any of the functions have
* completed. This function gets an error or result from the first function that
* completed. Invoked with (err, result).
@@ -44,6 +44,6 @@ export default function race(tasks, callback) {
if (!isArray(tasks)) return callback(new TypeError('First argument to race must be an array of functions'));
if (!tasks.length) return callback();
for (var i = 0, l = tasks.length; i < l; i++) {
- tasks[i](callback);
+ wrapAsync(tasks[i])(callback);
}
}
diff --git a/lib/reduce.js b/lib/reduce.js
index d2fe1c2..0d58c41 100644
--- a/lib/reduce.js
+++ b/lib/reduce.js
@@ -1,6 +1,7 @@
import eachOfSeries from './eachOfSeries';
import noop from 'lodash/noop';
import once from './internal/once';
+import wrapAsync from './internal/wrapAsync';
/**
* Reduces `coll` into a single value using an async `iteratee` to return each
@@ -22,12 +23,12 @@ import once from './internal/once';
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
* @param {*} memo - The initial state of the reduction.
- * @param {Function} iteratee - A function applied to each item in the
- * array to produce the next step in the reduction. The `iteratee` is passed a
- * `callback(err, reduction)` which accepts an optional error as its first
- * argument, and the state of the reduction as the second. If an error is
- * passed to the callback, the reduction is stopped and the main `callback` is
- * immediately called with the error. Invoked with (memo, item, callback).
+ * @param {AsyncFunction} iteratee - A function applied to each item in the
+ * array to produce the next step in the reduction.
+ * The `iteratee` should complete with the next state of the reduction.
+ * If the iteratee complete with an error, the reduction is stopped and the
+ * main `callback` is immediately called with the error.
+ * Invoked with (memo, item, callback).
* @param {Function} [callback] - A callback which is called after all the
* `iteratee` functions have finished. Result is the reduced value. Invoked with
* (err, result).
@@ -44,8 +45,9 @@ import once from './internal/once';
*/
export default function reduce(coll, memo, iteratee, callback) {
callback = once(callback || noop);
+ var _iteratee = wrapAsync(iteratee);
eachOfSeries(coll, function(x, i, callback) {
- iteratee(memo, x, function(err, v) {
+ _iteratee(memo, x, function(err, v) {
memo = v;
callback(err);
});
diff --git a/lib/reduceRight.js b/lib/reduceRight.js
index 844c94f..ca5aa7f 100644
--- a/lib/reduceRight.js
+++ b/lib/reduceRight.js
@@ -14,12 +14,12 @@ var slice = Array.prototype.slice;
* @category Collection
* @param {Array} array - A collection to iterate over.
* @param {*} memo - The initial state of the reduction.
- * @param {Function} iteratee - A function applied to each item in the
- * array to produce the next step in the reduction. The `iteratee` is passed a
- * `callback(err, reduction)` which accepts an optional error as its first
- * argument, and the state of the reduction as the second. If an error is
- * passed to the callback, the reduction is stopped and the main `callback` is
- * immediately called with the error. Invoked with (memo, item, callback).
+ * @param {AsyncFunction} iteratee - A function applied to each item in the
+ * array to produce the next step in the reduction.
+ * The `iteratee` should complete with the next state of the reduction.
+ * If the iteratee complete with an error, the reduction is stopped and the
+ * main `callback` is immediately called with the error.
+ * Invoked with (memo, item, callback).
* @param {Function} [callback] - A callback which is called after all the
* `iteratee` functions have finished. Result is the reduced value. Invoked with
* (err, result).
diff --git a/lib/reflect.js b/lib/reflect.js
index cc8d6b6..9e0613b 100644
--- a/lib/reflect.js
+++ b/lib/reflect.js
@@ -1,18 +1,19 @@
import initialParams from './internal/initialParams';
import rest from './internal/rest';
+import wrapAsync from './internal/wrapAsync';
/**
- * Wraps the function in another function that always returns data even when it
- * errors.
+ * Wraps the async function in another function that always completes with a
+ * result object, even when it errors.
*
- * The object returned has either the property `error` or `value`.
+ * The result object has either the property `error` or `value`.
*
* @name reflect
* @static
* @memberOf module:Utils
* @method
* @category Util
- * @param {Function} fn - The function you want to wrap
+ * @param {AsyncFunction} fn - The async function you want to wrap
* @returns {Function} - A function that always passes null to it's callback as
* the error. The second argument to the callback will be an `object` with
* either an `error` or a `value` property.
@@ -41,6 +42,7 @@ import rest from './internal/rest';
* });
*/
export default function reflect(fn) {
+ var _fn = wrapAsync(fn);
return initialParams(function reflectOn(args, reflectCallback) {
args.push(rest(function callback(err, cbArgs) {
if (err) {
@@ -60,6 +62,6 @@ export default function reflect(fn) {
}
}));
- return fn.apply(this, args);
+ return _fn.apply(this, args);
});
}
diff --git a/lib/reflectAll.js b/lib/reflectAll.js
index dbeba8d..0774b94 100644
--- a/lib/reflectAll.js
+++ b/lib/reflectAll.js
@@ -4,7 +4,7 @@ import _arrayMap from 'lodash/_arrayMap';
import forOwn from 'lodash/_baseForOwn';
/**
- * A helper function that wraps an array or an object of functions with reflect.
+ * A helper function that wraps an array or an object of functions with `reflect`.
*
* @name reflectAll
* @static
@@ -12,8 +12,9 @@ import forOwn from 'lodash/_baseForOwn';
* @method
* @see [async.reflect]{@link module:Utils.reflect}
* @category Util
- * @param {Array} tasks - The array of functions to wrap in `async.reflect`.
- * @returns {Array} Returns an array of functions, each function wrapped in
+ * @param {Array|Object|Iterable} tasks - The collection of
+ * [async functions]{@link AsyncFunction} to wrap in `async.reflect`.
+ * @returns {Array} Returns an array of async functions, each wrapped in
* `async.reflect`
* @example
*
diff --git a/lib/reject.js b/lib/reject.js
index 0ddbaf0..95a6270 100644
--- a/lib/reject.js
+++ b/lib/reject.js
@@ -11,9 +11,10 @@ import doParallel from './internal/doParallel';
* @see [async.filter]{@link module:Collections.filter}
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A truth test to apply to each item in `coll`.
- * The `iteratee` is passed a `callback(err, truthValue)`, which must be called
- * with a boolean argument once it has completed. Invoked with (item, callback).
+ * @param {Function} iteratee - An async truth test to apply to each item in
+ * `coll`.
+ * The should complete with a boolean value as its `result`.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called after all the
* `iteratee` functions have finished. Invoked with (err, results).
* @example
diff --git a/lib/rejectLimit.js b/lib/rejectLimit.js
index 977bc4c..8147811 100644
--- a/lib/rejectLimit.js
+++ b/lib/rejectLimit.js
@@ -13,9 +13,10 @@ import doParallelLimit from './internal/doParallelLimit';
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
* @param {number} limit - The maximum number of async operations at a time.
- * @param {Function} iteratee - A truth test to apply to each item in `coll`.
- * The `iteratee` is passed a `callback(err, truthValue)`, which must be called
- * with a boolean argument once it has completed. Invoked with (item, callback).
+ * @param {Function} iteratee - An async truth test to apply to each item in
+ * `coll`.
+ * The should complete with a boolean value as its `result`.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called after all the
* `iteratee` functions have finished. Invoked with (err, results).
*/
diff --git a/lib/rejectSeries.js b/lib/rejectSeries.js
index 0bb925e..7eba2f7 100644
--- a/lib/rejectSeries.js
+++ b/lib/rejectSeries.js
@@ -11,9 +11,10 @@ import doLimit from './internal/doLimit';
* @see [async.reject]{@link module:Collections.reject}
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A truth test to apply to each item in `coll`.
- * The `iteratee` is passed a `callback(err, truthValue)`, which must be called
- * with a boolean argument once it has completed. Invoked with (item, callback).
+ * @param {Function} iteratee - An async truth test to apply to each item in
+ * `coll`.
+ * The should complete with a boolean value as its `result`.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called after all the
* `iteratee` functions have finished. Invoked with (err, results).
*/
diff --git a/lib/retry.js b/lib/retry.js
index a5ad866..bd60644 100644
--- a/lib/retry.js
+++ b/lib/retry.js
@@ -1,5 +1,6 @@
import noop from 'lodash/noop';
import constant from 'lodash/constant';
+import wrapAsync from './internal/wrapAsync';
/**
* Attempts to get a successful response from `task` no more than `times` times
@@ -12,6 +13,7 @@ import constant from 'lodash/constant';
* @memberOf module:ControlFlow
* @method
* @category Control Flow
+ * @see [async.retryable]{@link module:ControlFlow.retryable}
* @param {Object|number} [opts = {times: 5, interval: 0}| 5] - Can be either an
* object with `times` and `interval` or a number.
* * `times` - The number of attempts to make before giving up. The default
@@ -26,16 +28,13 @@ import constant from 'lodash/constant';
* Invoked with (err).
* * If `opts` is a number, the number specifies the number of times to retry,
* with the default interval of `0`.
- * @param {Function} task - A function which receives two arguments: (1) a
- * `callback(err, result)` which must be called when finished, passing `err`
- * (which can be `null`) and the `result` of the function's execution, and (2)
- * a `results` object, containing the results of the previously executed
- * functions (if nested inside another control flow). Invoked with
- * (callback, results).
+ * @param {AsyncFunction} task - An async function to retry.
+ * Invoked with (callback).
* @param {Function} [callback] - An optional callback which is called when the
* task has succeeded, or after the final failed attempt. It receives the `err`
* and `result` arguments of the last attempt at completing the `task`. Invoked
* with (err, results).
+ *
* @example
*
* // The `retry` function can be used as a stand-alone control flow by passing
@@ -81,7 +80,7 @@ import constant from 'lodash/constant';
* // individual methods that are not as reliable, like this:
* async.auto({
* users: api.getUsers.bind(api),
- * payments: async.retry(3, api.getPayments.bind(api))
+ * payments: async.retryable(3, api.getPayments.bind(api))
* }, function(err, results) {
* // do something with the results
* });
@@ -124,9 +123,11 @@ export default function retry(opts, task, callback) {
throw new Error("Invalid arguments for async.retry");
}
+ var _task = wrapAsync(task);
+
var attempt = 1;
function retryAttempt() {
- task(function(err) {
+ _task(function(err) {
if (err && attempt++ < options.times &&
(typeof options.errorFilter != 'function' ||
options.errorFilter(err))) {
diff --git a/lib/retryable.js b/lib/retryable.js
index a541977..5741031 100644
--- a/lib/retryable.js
+++ b/lib/retryable.js
@@ -1,9 +1,11 @@
import retry from './retry';
import initialParams from './internal/initialParams';
+import wrapAsync from './internal/wrapAsync';
/**
- * A close relative of [`retry`]{@link module:ControlFlow.retry}. This method wraps a task and makes it
- * retryable, rather than immediately calling it with retries.
+ * A close relative of [`retry`]{@link module:ControlFlow.retry}. This method
+ * wraps a task and makes it retryable, rather than immediately calling it
+ * with retries.
*
* @name retryable
* @static
@@ -13,9 +15,12 @@ import initialParams from './internal/initialParams';
* @category Control Flow
* @param {Object|number} [opts = {times: 5, interval: 0}| 5] - optional
* options, exactly the same as from `retry`
- * @param {Function} task - the asynchronous function to wrap
- * @returns {Functions} The wrapped function, which when invoked, will retry on
- * an error, based on the parameters specified in `opts`.
+ * @param {AsyncFunction} task - the asynchronous function to wrap.
+ * This function will be passed any arguments passed to the returned wrapper.
+ * Invoked with (...args, callback).
+ * @returns {AsyncFunction} The wrapped function, which when invoked, will
+ * retry on an error, based on the parameters specified in `opts`.
+ * This function will accept the same parameters as `task`.
* @example
*
* async.auto({
@@ -30,9 +35,10 @@ export default function (opts, task) {
task = opts;
opts = null;
}
+ var _task = wrapAsync(task);
return initialParams(function (args, callback) {
function taskFn(cb) {
- task.apply(null, args.concat(cb));
+ _task.apply(null, args.concat(cb));
}
if (opts) retry(opts, taskFn, callback);
diff --git a/lib/seq.js b/lib/seq.js
index 8bd1121..4fceceb 100644
--- a/lib/seq.js
+++ b/lib/seq.js
@@ -1,6 +1,8 @@
import noop from 'lodash/noop';
import rest from './internal/rest';
import reduce from './reduce';
+import wrapAsync from './internal/wrapAsync';
+import arrayMap from 'lodash/_arrayMap';
/**
* Version of the compose function that is more natural to read. Each function
@@ -15,7 +17,7 @@ import reduce from './reduce';
* @method
* @see [async.compose]{@link module:ControlFlow.compose}
* @category Control Flow
- * @param {...Function} functions - the asynchronous functions to compose
+ * @param {...AsyncFunction} functions - the asynchronous functions to compose
* @returns {Function} a function that composes the `functions` in order
* @example
*
@@ -41,6 +43,7 @@ import reduce from './reduce';
* });
*/
export default rest(function seq(functions) {
+ var _functions = arrayMap(functions, wrapAsync);
return rest(function(args) {
var that = this;
@@ -51,7 +54,7 @@ export default rest(function seq(functions) {
cb = noop;
}
- reduce(functions, args, function(newargs, fn, cb) {
+ reduce(_functions, args, function(newargs, fn, cb) {
fn.apply(that, newargs.concat(rest(function(err, nextargs) {
cb(err, nextargs);
})));
diff --git a/lib/series.js b/lib/series.js
index 7955cf2..eef1534 100644
--- a/lib/series.js
+++ b/lib/series.js
@@ -27,9 +27,9 @@ import eachOfSeries from './eachOfSeries';
* @memberOf module:ControlFlow
* @method
* @category Control Flow
- * @param {Array|Iterable|Object} tasks - A collection containing functions to run, each
- * function is passed a `callback(err, result)` it must call on completion with
- * an error `err` (which can be `null`) and an optional `result` value.
+ * @param {Array|Iterable|Object} tasks - A collection containing
+ * [async functions]{@link AsyncFunction} to run in series.
+ * Each function can complete with any number of optional `result` values.
* @param {Function} [callback] - An optional callback to run once all the
* functions have completed. This function gets a results array (or object)
* containing all the result arguments passed to the `task` callbacks. Invoked
diff --git a/lib/some.js b/lib/some.js
index 3cb77e8..ce91ce8 100644
--- a/lib/some.js
+++ b/lib/some.js
@@ -14,10 +14,10 @@ import identity from 'lodash/identity';
* @alias any
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A truth test to apply to each item in the array
- * in parallel. The iteratee is passed a `callback(err, truthValue)` which must
- * be called with a boolean argument once it has completed. Invoked with
- * (item, callback).
+ * @param {AsyncFunction} iteratee - An async truth test to apply to each item
+ * in the collections in parallel.
+ * The iteratee should complete with a boolean `result` value.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called as soon as any
* iteratee returns `true`, or after all the iteratee functions have finished.
* Result will be either `true` or `false` depending on the values of the async
diff --git a/lib/someLimit.js b/lib/someLimit.js
index bf4c601..161c3cf 100644
--- a/lib/someLimit.js
+++ b/lib/someLimit.js
@@ -14,10 +14,10 @@ import identity from 'lodash/identity';
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
* @param {number} limit - The maximum number of async operations at a time.
- * @param {Function} iteratee - A truth test to apply to each item in the array
- * in parallel. The iteratee is passed a `callback(err, truthValue)` which must
- * be called with a boolean argument once it has completed. Invoked with
- * (item, callback).
+ * @param {AsyncFunction} iteratee - An async truth test to apply to each item
+ * in the collections in parallel.
+ * The iteratee should complete with a boolean `result` value.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called as soon as any
* iteratee returns `true`, or after all the iteratee functions have finished.
* Result will be either `true` or `false` depending on the values of the async
diff --git a/lib/someSeries.js b/lib/someSeries.js
index 8357a8b..8e278de 100644
--- a/lib/someSeries.js
+++ b/lib/someSeries.js
@@ -12,10 +12,10 @@ import doLimit from './internal/doLimit';
* @alias anySeries
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A truth test to apply to each item in the array
- * in parallel. The iteratee is passed a `callback(err, truthValue)` which must
- * be called with a boolean argument once it has completed. Invoked with
- * (item, callback).
+ * @param {AsyncFunction} iteratee - An async truth test to apply to each item
+ * in the collections in series.
+ * The iteratee should complete with a boolean `result` value.
+ * Invoked with (item, callback).
* @param {Function} [callback] - A callback which is called as soon as any
* iteratee returns `true`, or after all the iteratee functions have finished.
* Result will be either `true` or `false` depending on the values of the async
diff --git a/lib/sortBy.js b/lib/sortBy.js
index c829200..399debd 100644
--- a/lib/sortBy.js
+++ b/lib/sortBy.js
@@ -2,6 +2,7 @@ import arrayMap from 'lodash/_arrayMap';
import property from 'lodash/_baseProperty';
import map from './map';
+import wrapAsync from './internal/wrapAsync';
/**
* Sorts a list by the results of running each `coll` value through an async
@@ -13,10 +14,11 @@ import map from './map';
* @method
* @category Collection
* @param {Array|Iterable|Object} coll - A collection to iterate over.
- * @param {Function} iteratee - A function to apply to each item in `coll`.
- * The iteratee is passed a `callback(err, sortValue)` which must be called once
- * it has completed with an error (which can be `null`) and a value to use as
- * the sort criteria. Invoked with (item, callback).
+ * @param {AsyncFunction} iteratee - An async function to apply to each item in
+ * `coll`.
+ * The iteratee should complete with a value to use as the sort criteria as
+ * its `result`.
+ * Invoked with (item, callback).
* @param {Function} callback - A callback which is called after all the
* `iteratee` functions have finished, or an error occurs. Results is the items
* from the original `coll` sorted by the values returned by the `iteratee`
@@ -50,8 +52,9 @@ import map from './map';
* });
*/
export default function sortBy (coll, iteratee, callback) {
+ var _iteratee = wrapAsync(iteratee);
map(coll, function (x, callback) {
- iteratee(x, function (err, criteria) {
+ _iteratee(x, function (err, criteria) {
if (err) return callback(err);
callback(null, {value: x, criteria: criteria});
});
diff --git a/lib/timeout.js b/lib/timeout.js
index 93fe2e1..475b208 100644
--- a/lib/timeout.js
+++ b/lib/timeout.js
@@ -1,4 +1,5 @@
import initialParams from './internal/initialParams';
+import wrapAsync from './internal/wrapAsync';
/**
* Sets a time limit on an asynchronous function. If the function does not call
@@ -10,14 +11,13 @@ import initialParams from './internal/initialParams';
* @memberOf module:Utils
* @method
* @category Util
- * @param {Function} asyncFn - The asynchronous function you want to set the
- * time limit.
+ * @param {AsyncFunction} asyncFn - The async function to limit in time.
* @param {number} milliseconds - The specified time limit.
* @param {*} [info] - Any variable you want attached (`string`, `object`, etc)
* to timeout Error for more information..
- * @returns {Function} Returns a wrapped function that can be used with any of
- * the control flow functions. Invoke this function with the same
- * parameters as you would `asyncFunc`.
+ * @returns {AsyncFunction} Returns a wrapped function that can be used with any
+ * of the control flow functions.
+ * Invoke this function with the same parameters as you would `asyncFunc`.
* @example
*
* function myFunction(foo, callback) {
@@ -64,10 +64,12 @@ export default function timeout(asyncFn, milliseconds, info) {
originalCallback(error);
}
+ var fn = wrapAsync(asyncFn);
+
return initialParams(function (args, origCallback) {
originalCallback = origCallback;
// setup timer and call original function
timer = setTimeout(timeoutCallback, milliseconds);
- asyncFn.apply(null, args.concat(injectedCallback));
+ fn.apply(null, args.concat(injectedCallback));
});
}
diff --git a/lib/times.js b/lib/times.js
index bdd2e6b..ebd336c 100644
--- a/lib/times.js
+++ b/lib/times.js
@@ -12,8 +12,8 @@ import doLimit from './internal/doLimit';
* @see [async.map]{@link module:Collections.map}
* @category Control Flow
* @param {number} n - The number of times to run the function.
- * @param {Function} iteratee - The function to call `n` times. Invoked with the
- * iteration index and a callback (n, next).
+ * @param {AsyncFunction} iteratee - The async function to call `n` times.
+ * Invoked with the iteration index and a callback: (n, next).
* @param {Function} callback - see {@link module:Collections.map}.
* @example
*
diff --git a/lib/timesLimit.js b/lib/timesLimit.js
index 68d5ede..22be265 100644
--- a/lib/timesLimit.js
+++ b/lib/timesLimit.js
@@ -1,5 +1,6 @@
import mapLimit from './mapLimit';
import range from 'lodash/_baseRange';
+import wrapAsync from './internal/wrapAsync';
/**
* The same as [times]{@link module:ControlFlow.times} but runs a maximum of `limit` async operations at a
@@ -13,10 +14,11 @@ import range from 'lodash/_baseRange';
* @category Control Flow
* @param {number} count - The number of times to run the function.
* @param {number} limit - The maximum number of async operations at a time.
- * @param {Function} iteratee - The function to call `n` times. Invoked with the
- * iteration index and a callback (n, next).
+ * @param {AsyncFunction} iteratee - The async function to call `n` times.
+ * Invoked with the iteration index and a callback: (n, next).
* @param {Function} callback - see [async.map]{@link module:Collections.map}.
*/
export default function timeLimit(count, limit, iteratee, callback) {
- mapLimit(range(0, count, 1), limit, iteratee, callback);
+ var _iteratee = wrapAsync(iteratee);
+ mapLimit(range(0, count, 1), limit, _iteratee, callback);
}
diff --git a/lib/timesSeries.js b/lib/timesSeries.js
index 672428d..17ec0ca 100644
--- a/lib/timesSeries.js
+++ b/lib/timesSeries.js
@@ -11,8 +11,8 @@ import doLimit from './internal/doLimit';
* @see [async.times]{@link module:ControlFlow.times}
* @category Control Flow
* @param {number} n - The number of times to run the function.
- * @param {Function} iteratee - The function to call `n` times. Invoked with the
- * iteration index and a callback (n, next).
+ * @param {AsyncFunction} iteratee - The async function to call `n` times.
+ * Invoked with the iteration index and a callback: (n, next).
* @param {Function} callback - see {@link module:Collections.map}.
*/
export default doLimit(timesLimit, 1);
diff --git a/lib/transform.js b/lib/transform.js
index f001c51..ef254a1 100644
--- a/lib/transform.js
+++ b/lib/transform.js
@@ -3,6 +3,7 @@ import noop from 'lodash/noop';
import eachOf from './eachOf';
import once from './internal/once';
+import wrapAsync from './internal/wrapAsync';
/**
* A relative of `reduce`. Takes an Object or Array, and iterates over each
@@ -17,11 +18,8 @@ import once from './internal/once';
* @param {Array|Iterable|Object} coll - A collection to iterate over.
* @param {*} [accumulator] - The initial state of the transform. If omitted,
* it will default to an empty Object or Array, depending on the type of `coll`
- * @param {Function} iteratee - A function applied to each item in the
- * collection that potentially modifies the accumulator. The `iteratee` is
- * passed a `callback(err)` which accepts an optional error as its first
- * argument. If an error is passed to the callback, the transform is stopped
- * and the main `callback` is immediately called with the error.
+ * @param {AsyncFunction} iteratee - A function applied to each item in the
+ * collection that potentially modifies the accumulator.
* Invoked with (accumulator, item, key, callback).
* @param {Function} [callback] - A callback which is called after all the
* `iteratee` functions have finished. Result is the transformed accumulator.
@@ -56,9 +54,10 @@ export default function transform (coll, accumulator, iteratee, callback) {
accumulator = isArray(coll) ? [] : {};
}
callback = once(callback || noop);
+ var _iteratee = wrapAsync(iteratee);
eachOf(coll, function(v, k, cb) {
- iteratee(accumulator, v, k, cb);
+ _iteratee(accumulator, v, k, cb);
}, function(err) {
callback(err, accumulator);
});
diff --git a/lib/unmemoize.js b/lib/unmemoize.js
index 4b2db4d..d89075f 100644
--- a/lib/unmemoize.js
+++ b/lib/unmemoize.js
@@ -8,8 +8,8 @@
* @method
* @see [async.memoize]{@link module:Utils.memoize}
* @category Util
- * @param {Function} fn - the memoized function
- * @returns {Function} a function that calls the original unmemoized function
+ * @param {AsyncFunction} fn - the memoized function
+ * @returns {AsyncFunction} a function that calls the original unmemoized function
*/
export default function unmemoize(fn) {
return function () {
diff --git a/lib/until.js b/lib/until.js
index 7b0b0b5..942a381 100644
--- a/lib/until.js
+++ b/lib/until.js
@@ -1,9 +1,9 @@
import whilst from './whilst';
/**
- * Repeatedly call `fn` until `test` returns `true`. Calls `callback` when
+ * Repeatedly call `iteratee` until `test` returns `true`. Calls `callback` when
* stopped, or an error occurs. `callback` will be passed an error and any
- * arguments passed to the final `fn`'s callback.
+ * arguments passed to the final `iteratee`'s callback.
*
* The inverse of [whilst]{@link module:ControlFlow.whilst}.
*
@@ -14,17 +14,16 @@ import whilst from './whilst';
* @see [async.whilst]{@link module:ControlFlow.whilst}
* @category Control Flow
* @param {Function} test - synchronous truth test to perform before each
- * execution of `fn`. Invoked with ().
- * @param {Function} fn - A function which is called each time `test` fails.
- * The function is passed a `callback(err)`, which must be called once it has
- * completed with an optional `err` argument. Invoked with (callback).
+ * execution of `iteratee`. Invoked with ().
+ * @param {AsyncFunction} iteratee - An async function which is called each time
+ * `test` fails. Invoked with (callback).
* @param {Function} [callback] - A callback which is called after the test
- * function has passed and repeated execution of `fn` has stopped. `callback`
- * will be passed an error and any arguments passed to the final `fn`'s
+ * function has passed and repeated execution of `iteratee` has stopped. `callback`
+ * will be passed an error and any arguments passed to the final `iteratee`'s
* callback. Invoked with (err, [results]);
*/
-export default function until(test, fn, callback) {
+export default function until(test, iteratee, callback) {
whilst(function() {
return !test.apply(this, arguments);
- }, fn, callback);
+ }, iteratee, callback);
}
diff --git a/lib/waterfall.js b/lib/waterfall.js
index 7bc60da..24befac 100644
--- a/lib/waterfall.js
+++ b/lib/waterfall.js
@@ -4,6 +4,7 @@ import once from './internal/once';
import rest from './internal/rest';
import onlyOnce from './internal/onlyOnce';
+import wrapAsync from './internal/wrapAsync';
/**
* Runs the `tasks` array of functions in series, each passing their results to
@@ -16,10 +17,10 @@ import onlyOnce from './internal/onlyOnce';
* @memberOf module:ControlFlow
* @method
* @category Control Flow
- * @param {Array} tasks - An array of functions to run, each function is passed
- * a `callback(err, result1, result2, ...)` it must call on completion. The
- * first argument is an error (which can be `null`) and any further arguments
- * will be passed as arguments in order to the next task.
+ * @param {Array} tasks - An array of [async functions]{@link AsyncFunction}
+ * to run.
+ * Each function should complete with any number of `result` values.
+ * The `result` values will be passed as arguments, in order, to the next task.
* @param {Function} [callback] - An optional callback to run once all the
* functions have completed. This will be passed the results of the last task's
* callback. Invoked with (err, [results]).
@@ -82,7 +83,7 @@ export default function(tasks, callback) {
args.push(taskCallback);
- var task = tasks[taskIndex++];
+ var task = wrapAsync(tasks[taskIndex++]);
task.apply(null, args);
}
diff --git a/lib/whilst.js b/lib/whilst.js
index ac2a79c..57edad6 100644
--- a/lib/whilst.js
+++ b/lib/whilst.js
@@ -2,6 +2,7 @@ import noop from 'lodash/noop';
import rest from './internal/rest';
import onlyOnce from './internal/onlyOnce';
+import wrapAsync from './internal/wrapAsync';
/**
* Repeatedly call `iteratee`, while `test` returns `true`. Calls `callback` when
@@ -14,9 +15,8 @@ import onlyOnce from './internal/onlyOnce';
* @category Control Flow
* @param {Function} test - synchronous truth test to perform before each
* execution of `iteratee`. Invoked with ().
- * @param {Function} iteratee - A function which is called each time `test` passes.
- * The function is passed a `callback(err)`, which must be called once it has
- * completed with an optional `err` argument. Invoked with (callback).
+ * @param {AsyncFunction} iteratee - An async function which is called each time
+ * `test` passes. Invoked with (callback).
* @param {Function} [callback] - A callback which is called after the test
* function has failed and repeated execution of `iteratee` has stopped. `callback`
* will be passed an error and any arguments passed to the final `iteratee`'s
@@ -40,11 +40,12 @@ import onlyOnce from './internal/onlyOnce';
*/
export default function whilst(test, iteratee, callback) {
callback = onlyOnce(callback || noop);
+ var _iteratee = wrapAsync(iteratee);
if (!test()) return callback(null);
var next = rest(function(err, args) {
if (err) return callback(err);
- if (test()) return iteratee(next);
+ if (test()) return _iteratee(next);
callback.apply(null, [null].concat(args));
});
- iteratee(next);
+ _iteratee(next);
}
diff --git a/mocha_test/asyncFunctions.js b/mocha_test/asyncFunctions.js
new file mode 100644
index 0000000..b756a90
--- /dev/null
+++ b/mocha_test/asyncFunctions.js
@@ -0,0 +1,11 @@
+var supportsAsync = require('../lib/internal/wrapAsync').supportsAsync;
+
+describe('async function support', function () {
+ this.timeout(100);
+
+ if (supportsAsync()) {
+ require('./es2017/asyncFunctions.js')();
+ } else {
+ it('should not test async functions in this environment');
+ }
+});
diff --git a/mocha_test/es2017/asyncFunctions.js b/mocha_test/es2017/asyncFunctions.js
new file mode 100644
index 0000000..ca76a56
--- /dev/null
+++ b/mocha_test/es2017/asyncFunctions.js
@@ -0,0 +1,682 @@
+var async = require('../../lib');
+const expect = require('chai').expect;
+const assert = require('assert');
+
+
+module.exports = function () {
+ async function asyncIdentity(val) {
+ var res = await Promise.resolve(val);
+ return res;
+ }
+
+ const input = [1, 2, 3];
+ const inputObj = {a: 1, b: 2, c: 3};
+
+ it('should asyncify async functions', (done) => {
+ async.asyncify(asyncIdentity)(42, (err, val) => {
+ assert(val === 42);
+ done(err);
+ })
+ });
+
+ it('should handle errors in async functions', (done) => {
+ async.asyncify(async function () {
+ throw new Error('thrown error')
+ })((err) => {
+ assert(err.message = 'thrown error');
+ done();
+ })
+ });
+
+ /*
+ * Collections
+ */
+
+ it('should handle async functions in each', (done) => {
+ async.each(input, asyncIdentity, done);
+ });
+
+ it('should handle async functions in eachLimit', (done) => {
+ async.eachLimit(input, 2, asyncIdentity, done);
+ });
+
+ it('should handle async functions in eachSeries', (done) => {
+ async.eachSeries(input, asyncIdentity, done);
+ });
+
+ it('should handle async functions in eachOf', (done) => {
+ async.eachOf(input, asyncIdentity, done);
+ });
+
+ it('should handle async functions in eachOfLimit', (done) => {
+ async.eachOfLimit(input, 2, asyncIdentity, done);
+ });
+
+ it('should handle async functions in eachOfSeries', (done) => {
+ async.eachOfSeries(input, asyncIdentity, done);
+ });
+
+ it('should handle async functions in map', (done) => {
+ async.map(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql(input);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in mapLimit', (done) => {
+ async.mapLimit(input, 2, asyncIdentity, (err, result) => {
+ expect(result).to.eql(input);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in mapSeries', (done) => {
+ async.mapSeries(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql(input);
+ done(err);
+ });
+ });
+
+
+ it('should handle async functions in mapValues', (done) => {
+ async.mapValues(inputObj, asyncIdentity, (err, result) => {
+ expect(result).to.eql(inputObj);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in mapValuesLimit', (done) => {
+ async.mapValuesLimit(inputObj, 2, asyncIdentity, (err, result) => {
+ expect(result).to.eql(inputObj);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in mapValuesSeries', (done) => {
+ async.mapValuesSeries(inputObj, asyncIdentity, (err, result) => {
+ expect(result).to.eql(inputObj);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in filter', (done) => {
+ async.filter(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql(input);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in filterLimit', (done) => {
+ async.filterLimit(input, 2, asyncIdentity, (err, result) => {
+ expect(result).to.eql(input);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in filterSeries', (done) => {
+ async.filterSeries(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql(input);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in reject', (done) => {
+ async.reject(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql([]);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in rejectLimit', (done) => {
+ async.rejectLimit(input, 2, asyncIdentity, (err, result) => {
+ expect(result).to.eql([]);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in rejectSeries', (done) => {
+ async.rejectSeries(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql([]);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in every', (done) => {
+ async.every(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql(true);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in everyLimit', (done) => {
+ async.everyLimit(input, 2, asyncIdentity, (err, result) => {
+ expect(result).to.eql(true);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in everySeries', (done) => {
+ async.everySeries(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql(true);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in some', (done) => {
+ async.some(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql(true);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in someLimit', (done) => {
+ async.someLimit(input, 2, asyncIdentity, (err, result) => {
+ expect(result).to.eql(true);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in someSeries', (done) => {
+ async.someSeries(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql(true);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in groupBy', (done) => {
+ async.groupBy(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql({1: [1], 2: [2], 3: [3]});
+ done(err);
+ });
+ });
+
+ it('should handle async functions in groupByLimit', (done) => {
+ async.groupByLimit(input, 2, asyncIdentity, (err, result) => {
+ expect(result).to.eql({1: [1], 2: [2], 3: [3]});
+ done(err);
+ });
+ });
+
+ it('should handle async functions in groupBySeries', (done) => {
+ async.groupBySeries(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql({1: [1], 2: [2], 3: [3]});
+ done(err);
+ });
+ });
+
+
+ it('should handle async functions in concat', (done) => {
+ async.concat(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql(input);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in concatSeries', (done) => {
+ async.concatSeries(input, asyncIdentity, (err, result) => {
+ expect(result).to.eql(input);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in reduce', (done) => {
+ async.reduce(input, 0, async function (acc, val) {
+ var res = await Promise.resolve(acc + val);
+ return res;
+ },
+ (err, result) => {
+ expect(result).to.eql(6);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in reduceRight', (done) => {
+ async.reduceRight(input, 0, async function (acc, val) {
+ var res = await Promise.resolve(acc + val);
+ return res;
+ },
+ (err, result) => {
+ expect(result).to.eql(6);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in sortBy', (done) => {
+ async.sortBy([3, 2, 1], asyncIdentity, (err, result) => {
+ expect(result).to.eql(input);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in transform', (done) => {
+ async.transform(inputObj, async function (obj, val, key) {
+ obj[key] = await Promise.resolve(val);
+ }, (err, result) => {
+ expect(result).to.eql(inputObj);
+ done(err);
+ });
+ });
+
+ /*
+ * Control Flow
+ */
+
+ it('should handle async functions in applyEach', (done) => {
+ async.applyEach([asyncIdentity, asyncIdentity])(input, (err, result) => {
+ expect(result).to.eql([input, input]);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in applyEachSeries', (done) => {
+ async.applyEachSeries([asyncIdentity, asyncIdentity])(input, (err, result) => {
+ expect(result).to.eql([input, input]);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in auto', (done) => {
+ async.auto({
+ a: async function () {
+ return await Promise.resolve(1);
+ },
+ b: async function () {
+ return await Promise.resolve(2);
+ },
+ c: ['a', 'b', async function (results) {
+ return await Promise.resolve(results.a + results.b);
+ }]
+ }, (err, result) => {
+ expect(result).to.eql({a: 1, b: 2, c: 3});
+ done(err);
+ });
+ });
+
+ it('should handle async functions in autoInject', (done) => {
+ async.autoInject({
+ a: async function () {
+ return await Promise.resolve(1);
+ },
+ b: async function (a) {
+ return await Promise.resolve(a + 1);
+ },
+ c: async (a, b) => {
+ return await Promise.resolve(a + b);
+ },
+ d: async (c) => {
+ return await Promise.resolve(c + 1);
+ }
+ }, (err, result) => {
+ expect(result).to.eql({a: 1, b: 2, c: 3, d: 4});
+ done(err);
+ });
+ });
+
+ it('should handle async functions in autoInject (shorthand)', (done) => {
+ async.autoInject({
+ async a() {
+ return await Promise.resolve(1);
+ },
+ async b(a) {
+ return await Promise.resolve(a + 1);
+ },
+ async c(a, b) {
+ return await Promise.resolve(a + b);
+ },
+ async d(c) {
+ return await Promise.resolve(c + 1);
+ }
+ }, (err, result) => {
+ expect(result).to.eql({a: 1, b: 2, c: 3, d: 4});
+ done(err);
+ });
+ });
+
+ it('should handle async functions in cargo', (done) => {
+ var result = [];
+ var q = async.cargo(async function(val) {
+ result.push(await Promise.resolve(val));
+ }, 2)
+
+ q.drain = () => {
+ expect(result).to.eql([[1, 2], [3]]);
+ done();
+ };
+
+ q.push(1);
+ q.push(2);
+ q.push(3);
+ });
+
+ it('should handle async functions in queue', (done) => {
+ var result = [];
+ var q = async.queue(async function(val) {
+ result.push(await Promise.resolve(val));
+ }, 2)
+
+ q.drain = () => {
+ expect(result).to.eql([1, 2, 3]);
+ done();
+ };
+
+ q.push(1);
+ q.push(2);
+ q.push(3);
+ });
+
+ it('should handle async functions in priorityQueue', (done) => {
+ var result = [];
+ var q = async.priorityQueue(async function(val) {
+ result.push(await Promise.resolve(val));
+ }, 2)
+
+ q.drain = () => {
+ expect(result).to.eql([1, 2, 3]);
+ done();
+ };
+
+ q.push(1);
+ q.push(2);
+ q.push(3);
+ });
+
+ it('should handle async functions in compose', (done) => {
+ async.compose(
+ async (a) => a + 1,
+ async (a) => a + 1,
+ async (a) => a + 1
+ )(0, (err, result) => {
+ expect(result).to.equal(3);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in seq', (done) => {
+ async.seq(
+ async (a) => a + 1,
+ async (a) => a + 1,
+ async (a) => a + 1
+ )(0, (err, result) => {
+ expect(result).to.equal(3);
+ done(err);
+ });
+ });
+
+ it('should handle async functions in during', (done) => {
+ var val = 0;
+ async.during(async () => {
+ return val < 3;
+ },
+ async () => {
+ val += 1;
+ return val;
+ }, done);
+ });
+
+ it('should handle async functions in doDuring', (done) => {
+ var val = 0;
+ async.doDuring(async () => {
+ val += 1;
+ return val;
+ },
+ async (res) => {
+ return res < 3;
+ }, done);
+ });
+
+ it('should handle async functions in whilst', (done) => {
+ var val = 0;
+ async.whilst(() => val < 3,
+ async () => {
+ val += 1;
+ return val;
+ }, done);
+ });
+
+ it('should handle async functions in doWhilst', (done) => {
+ var val = 0;
+ async.doWhilst(async () => {
+ val += 1;
+ return val;
+ }, (res) => res < 3, done);
+ });
+
+ it('should handle async functions in until', (done) => {
+ var val = 0;
+ async.until(() => val > 3,
+ async () => {
+ val += 1;
+ return val;
+ }, done);
+ });
+
+ it('should handle async functions in doUntil', (done) => {
+ var val = 0;
+ async.doUntil(async () => {
+ val += 1;
+ return val;
+ }, (res) => res > 3, done);
+ });
+
+ it('should handle async functions in forever', (done) => {
+ var counter = 0;
+ async.forever(async () => {
+ counter += 1;
+ if (counter > 10) throw new Error('too big');
+ },(err) => {
+ expect(err.message).to.equal('too big');
+ done();
+ })
+ });
+
+ it('should handle async functions in parallel', (done) => {
+ async.parallel([
+ async () => 1,
+ async () => 2,
+ async () => 3
+ ], (err, result) => {
+ expect(result).to.eql([1, 2, 3]);
+ done(err);
+ })
+ });
+
+ it('should handle async functions in parallel (object)', (done) => {
+ async.parallel({
+ a: async () => 1,
+ b: async () => 2,
+ c: async () => 3
+ }, (err, result) => {
+ expect(result).to.eql({a: 1, b: 2, c: 3});
+ done(err);
+ })
+ });
+
+ it('should handle async functions in parallelLimit', (done) => {
+ async.parallelLimit([
+ async () => 1,
+ async () => 2,
+ async () => 3
+ ], 2, (err, result) => {
+ expect(result).to.eql([1, 2, 3]);
+ done(err);
+ })
+ });
+
+ it('should handle async functions in parallelLimit (object)', (done) => {
+ async.parallelLimit({
+ a: async () => 1,
+ b: async () => 2,
+ c: async () => 3
+ }, 2, (err, result) => {
+ expect(result).to.eql({a: 1, b: 2, c: 3});
+ done(err);
+ })
+ });
+
+ it('should handle async functions in series', (done) => {
+ async.series([
+ async () => 1,
+ async () => 2,
+ async () => 3
+ ], (err, result) => {
+ expect(result).to.eql([1, 2, 3]);
+ done(err);
+ })
+ });
+
+ it('should handle async functions in series (object)', (done) => {
+ async.series({
+ a: async () => 1,
+ b: async () => 2,
+ c: async () => 3
+ }, (err, result) => {
+ expect(result).to.eql({a: 1, b: 2, c: 3});
+ done(err);
+ })
+ });
+
+ it('should handle async functions in race', (done) => {
+ async.race([
+ async () => 1,
+ async () => 2,
+ async () => 3
+ ], (err, result) => {
+ expect(result).to.eql(1);
+ done(err);
+ })
+ });
+
+ it('should handle async functions in retry', (done) => {
+ var count = 0;
+ async.retry(4, async () => {
+ count += 1;
+ if (count < 3) throw new Error('fail');
+ return count;
+ }, (err, result) => {
+ expect(result).to.eql(3);
+ done(err);
+ })
+ });
+
+ it('should handle async functions in retryable', (done) => {
+ var count = 0;
+ async.retryable(4, async () => {
+ count += 1;
+ if (count < 3) throw new Error('fail');
+ return count;
+ })((err, result) => {
+ expect(result).to.eql(3);
+ done(err);
+ })
+ });
+
+ it('should handle async functions in times', (done) => {
+ var count = 0;
+ async.times(4, async () => {
+ count += 1;
+ return count;
+ }, (err, result) => {
+ expect(result).to.eql([1, 2, 3, 4]);
+ done(err);
+ })
+ });
+
+ it('should handle async functions in timesLimit', (done) => {
+ var count = 0;
+ async.timesLimit(4, 2, async () => {
+ count += 1;
+ return count;
+ }, (err, result) => {
+ expect(result).to.eql([1, 2, 3, 4]);
+ done(err);
+ })
+ });
+
+ it('should handle async functions in timesSeries', (done) => {
+ var count = 0;
+ async.timesSeries(4, async () => {
+ count += 1;
+ return count;
+ }, (err, result) => {
+ expect(result).to.eql([1, 2, 3, 4]);
+ done(err);
+ })
+ });
+
+ it('should handle async functions in waterfall', (done) => {
+ async.waterfall([
+ async () => 1,
+ async (a) => a + 1,
+ async (a) => [a, a + 1],
+ async ([a, b]) => a + b,
+ ], (err, result) => {
+ expect(result).to.eql(5);
+ done(err);
+ })
+ });
+
+ /**
+ * Utils
+ */
+
+ it('should handle async functions in dir', (done) => {
+ async.dir(async (val) => val, 'foo');
+ setTimeout(done);
+ });
+
+ it('should handle async functions in log', (done) => {
+ async.log(async (val) => val, 'foo');
+ setTimeout(done);
+ });
+
+ it('should handle async functions in ensureAsync', () => {
+ var fn = async.ensureAsync(asyncIdentity);
+ assert(fn === asyncIdentity);
+ });
+
+ it('should handle async functions in memoize', (done) => {
+ var fn = async.memoize(asyncIdentity);
+ fn(1, () => {
+ fn(1, done);
+ })
+ });
+
+ it('should handle async functions in reflect', (done) => {
+ var fn = async.reflect(asyncIdentity);
+ fn(1, (err, result) => {
+ expect(result).to.eql({value: 1});
+ done(err);
+ })
+ });
+
+ it('should handle async functions in reflect (error case)', (done) => {
+ var thrown;
+ var fn = async.reflect(async () => {
+ thrown = new Error('foo');
+ throw thrown;
+ });
+ fn(1, (err, result) => {
+ expect(result).to.eql({error: thrown});
+ done(err);
+ })
+ });
+
+ it('should handle async functions in timeout', (done) => {
+ var fn = async.timeout(asyncIdentity, 50);
+ fn(1, (err, result) => {
+ expect(result).to.eql(1);
+ done(err);
+ })
+ });
+
+ it('should handle async functions in timeout (error case)', (done) => {
+ var fn = async.timeout(async (val) => {
+ await new Promise((resolve) => setTimeout(resolve, 100));
+ return val;
+ }, 50);
+ fn(1, (err) => {
+ expect(err.message).to.match(/timed out/);
+ done();
+ })
+ });
+}
diff --git a/package.json b/package.json
index a7812b3..34dff0b 100644
--- a/package.json
+++ b/package.json
@@ -22,12 +22,13 @@
"lodash-es": "^4.14.0"
},
"devDependencies": {
- "babel-cli": "^6.16.0",
- "babel-core": "^6.3.26",
+ "babel-cli": "^6.24.0",
+ "babel-core": "^6.24.0",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-istanbul": "^2.0.1",
"babel-plugin-transform-es2015-modules-commonjs": "^6.3.16",
"babel-preset-es2015": "^6.3.13",
+ "babel-preset-es2017": "^6.22.0",
"babelify": "^7.2.0",
"benchmark": "^2.1.1",
"bluebird": "^3.4.6",