diff --git a/.eslintrc b/.eslintrc index 2644f5cc6..2627332f2 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 ff46739c1..989efb642 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ node_js: - "0.10" - "0.12" - "4" + - "6" + - "7" matrix: include: @@ -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/lib/asyncify.js b/lib/asyncify.js index dec39d239..61794fb05 100644 --- a/lib/asyncify.js +++ b/lib/asyncify.js @@ -48,7 +48,7 @@ import initialParams from './internal/initialParams'; * } * ], callback); * - * // es6 example + * // es2017 example * var q = async.queue(async.asyncify(async function(file) { * var intermediateStep = await processFile(file); * return await somePromise(intermediateStep) diff --git a/lib/each.js b/lib/each.js index 5bf6bd4d6..e20b96516 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. @@ -61,5 +62,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 e2ed79088..c3bc595d0 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. @@ -23,5 +24,5 @@ import withoutIndex from './internal/withoutIndex'; * `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 798f270ac..1cfa171dc 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) { @@ -76,5 +77,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 c3b4567fd..17dffc11b 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 @@ -23,5 +24,5 @@ import _eachOfLimit from './internal/eachOfLimit'; * `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/internal/filter.js b/lib/internal/filter.js index 5af788c5d..032bd336b 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 453cd29be..9cd927e2c 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/wrapAsync.js b/lib/internal/wrapAsync.js new file mode 100644 index 000000000..90e07020c --- /dev/null +++ b/lib/internal/wrapAsync.js @@ -0,0 +1,11 @@ +import asyncify from '../asyncify'; + +var supportsSymbol = typeof Symbol !== 'undefined'; + +export default function wrapAsync(asyncFn) { + if (!supportsSymbol) return asyncFn; + + var isAsync = asyncFn[Symbol.toStringTag] === 'AsyncFunction'; + + return isAsync ? asyncify(asyncFn) : asyncFn; +} diff --git a/mocha_test/asyncFunctions.js b/mocha_test/asyncFunctions.js new file mode 100644 index 000000000..67e1b161e --- /dev/null +++ b/mocha_test/asyncFunctions.js @@ -0,0 +1,20 @@ +describe('async function support', function () { + this.timeout(100); + + var supportsAsync; + var supportsSymbol = typeof Symbol !== 'undefined'; + try { + /* eslint no-eval:0 */ + var fn = eval('(async function() {})') + supportsAsync = supportsSymbol && + fn[Symbol.toStringTag] === 'AsyncFunction'; + } catch (e) { + supportsAsync = false; + } + + 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 000000000..46bd6ca7c --- /dev/null +++ b/mocha_test/es2017/asyncFunctions.js @@ -0,0 +1,86 @@ +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]; + + it('should asyncify async functions', (done) => { + async.asyncify(asyncIdentity)(42, (err, val) => { + assert(val === 42); + done(err); + }) + }); + + 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 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); + }); + }); +} diff --git a/package.json b/package.json index 1082cb66c..6e9427a69 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",