diff --git a/lib/internal/eachOfLimit.js b/lib/internal/eachOfLimit.js index 4b7c7efa9..53d05b3a2 100644 --- a/lib/internal/eachOfLimit.js +++ b/lib/internal/eachOfLimit.js @@ -3,14 +3,14 @@ import noop from 'lodash/noop'; import once from 'lodash/once'; -import keyIterator from './keyIterator'; +import iterator from './iterator'; import onlyOnce from './onlyOnce'; export default function _eachOfLimit(limit) { return function (obj, iteratee, callback) { callback = once(callback || noop); obj = obj || []; - var nextKey = keyIterator(obj); + var nextElem = iterator(obj); if (limit <= 0) { return callback(null); } @@ -24,8 +24,8 @@ export default function _eachOfLimit(limit) { } while (running < limit && !errored) { - var key = nextKey(); - if (key === null) { + var elem = nextElem(); + if (elem === null) { done = true; if (running <= 0) { callback(null); @@ -33,7 +33,7 @@ export default function _eachOfLimit(limit) { return; } running += 1; - iteratee(obj[key], key, onlyOnce(function (err) { + iteratee(elem.value, elem.key, onlyOnce(function (err) { running -= 1; if (err) { callback(err); diff --git a/lib/internal/iterator.js b/lib/internal/iterator.js new file mode 100644 index 000000000..d83203941 --- /dev/null +++ b/lib/internal/iterator.js @@ -0,0 +1,38 @@ +'use strict'; + +import isArrayLike from 'lodash/isArrayLike'; +import keys from 'lodash/keys'; + +var iteratorSymbol = typeof Symbol === 'function' && Symbol.iterator; + +export default function iterator(coll) { + var i = -1; + var len; + if (isArrayLike(coll)) { + len = coll.length; + return function next() { + i++; + return i < len ? {value: coll[i], key: i} : null; + }; + } + + if (iteratorSymbol && coll[iteratorSymbol]) { + var iterate = coll[iteratorSymbol](); + + return function next() { + var item = iterate.next(); + if (item.done) + return null; + i++; + return {value: item.value, key: i}; + }; + } + + var okeys = keys(coll); + len = okeys.length; + return function next() { + i++; + var key = okeys[i]; + return i < len ? {value: coll[key], key: key} : null; + }; +} diff --git a/lib/internal/keyIterator.js b/lib/internal/keyIterator.js deleted file mode 100644 index 0e2b0c348..000000000 --- a/lib/internal/keyIterator.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -import isArrayLike from 'lodash/isArrayLike'; -import keys from 'lodash/keys'; - -export default function keyIterator(coll) { - var i = -1; - var len; - if (isArrayLike(coll)) { - len = coll.length; - return function next() { - i++; - return i < len ? i : null; - }; - } else { - var okeys = keys(coll); - len = okeys.length; - return function next() { - i++; - return i < len ? okeys[i] : null; - }; - } -} diff --git a/test/test-async.js b/test/test-async.js index f12d7c170..047c7f9fc 100755 --- a/test/test-async.js +++ b/test/test-async.js @@ -867,6 +867,36 @@ exports['forEachOf with array'] = function(test){ }); }; +exports['forEachOf with Set (iterators)'] = function(test){ + if (typeof Set !== 'function') + return test.done(); + + var args = []; + var set = new Set(); + set.add("a"); + set.add("b"); + async.forEachOf(set, forEachOfIteratee.bind(this, args), function(err){ + if (err) throw err; + test.same(args, [0, "a", 1, "b"]); + test.done(); + }); +}; + +exports['forEachOf with Map (iterators)'] = function(test){ + if (typeof Map !== 'function') + return test.done(); + + var args = []; + var map = new Map(); + map.set(1, "a"); + map.set(2, "b"); + async.forEachOf(map, forEachOfIteratee.bind(this, args), function(err){ + if (err) throw err; + test.same(args, [0, [1, "a"], 1, [2, "b"]]); + test.done(); + }); +}; + exports['eachSeries'] = function(test){ var args = []; async.eachSeries([1,3,2], eachIteratee.bind(this, args), function(err){ @@ -1116,6 +1146,35 @@ exports['forEachOfSeries with array'] = function(test){ }); }; +exports['forEachOfSeries with Set (iterators)'] = function(test){ + if (typeof Set !== 'function') + return test.done(); + + var args = []; + var set = new Set(); + set.add("a"); + set.add("b"); + async.forEachOfSeries(set, forEachOfIteratee.bind(this, args), function(err){ + if (err) throw err; + test.same(args, [0, "a", 1, "b"]); + test.done(); + }); +}; + +exports['forEachOfSeries with Map (iterators)'] = function(test){ + if (typeof Map !== 'function') + return test.done(); + + var args = []; + var map = new Map(); + map.set(1, "a"); + map.set(2, "b"); + async.forEachOfSeries(map, forEachOfIteratee.bind(this, args), function(err){ + if (err) throw err; + test.same(args, [0, [1, "a"], 1, [2, "b"]]); + test.done(); + }); +}; exports['eachOfLimit alias'] = function(test){ test.equals(async.eachOfLimit, async.forEachOfLimit); @@ -1233,6 +1292,36 @@ exports['forEachOfLimit with array'] = function(test){ }); }; +exports['forEachOfLimit with Set (iterators)'] = function(test){ + if (typeof Set !== 'function') + return test.done(); + + var args = []; + var set = new Set(); + set.add("a"); + set.add("b"); + async.forEachOfLimit(set, 1, forEachOfIteratee.bind(this, args), function(err){ + if (err) throw err; + test.same(args, [0, "a", 1, "b"]); + test.done(); + }); +}; + +exports['forEachOfLimit with Map (iterators)'] = function(test){ + if (typeof Map !== 'function') + return test.done(); + + var args = []; + var map = new Map(); + map.set(1, "a"); + map.set(2, "b"); + async.forEachOfLimit(map, 1, forEachOfIteratee.bind(this, args), function(err){ + if (err) throw err; + test.same(args, [0, [1, "a"], 1, [2, "b"]]); + test.done(); + }); +}; + exports['map'] = { 'basic': function(test){