diff --git a/lib/async.js b/lib/async.js index dec593980..314432e91 100644 --- a/lib/async.js +++ b/lib/async.js @@ -107,11 +107,24 @@ return keys; }; - function _iteratorKeys(coll) { - return _isArrayLike(coll) ? - // just plain _keys wont work with sparse arrays - _map(coll, function (_, index) { return index; }) : - _keys(coll); + function _keyIterator(coll) { + var i = -1; + var len; + var keys; + if (_isArrayLike(coll)) { + len = coll.length; + return function next() { + i++; + return i < len ? i : null; + }; + } else { + keys = _keys(coll); + len = keys.length; + return function next() { + i++; + return i < len ? keys[i] : null; + }; + } } function _baseSlice(arr, start) { @@ -219,32 +232,24 @@ async.forEachOfSeries = async.eachOfSeries = function (obj, iterator, callback) { callback = callback || noop; - var keys = _iteratorKeys(obj); - var size = keys.length; - if (!size) { - return callback(); - } - var completed = 0; + var nextKey = _keyIterator(obj); function iterate() { var sync = true; - var key = keys[completed]; + var key = nextKey(); + if (key === null) { + return callback(null); + } iterator(obj[key], key, function (err) { if (err) { callback(err); callback = noop; } else { - completed += 1; - if (completed >= size) { - callback(null); + if (sync) { + async.nextTick(iterate); } else { - if (sync) { - async.nextTick(iterate); - } - else { - iterate(); - } + iterate(); } } }); @@ -264,40 +269,41 @@ return function (obj, iterator, callback) { callback = callback || noop; - var keys = _iteratorKeys(obj); - var size = keys.length; - if (!size || limit <= 0) { + var nextKey = _keyIterator(obj); + if (limit <= 0) { return callback(null); } - var completed = 0; - var started = 0; + var done = false; var running = 0; var errored = false; (function replenish () { - if (completed >= size) { - return callback(); + if (done && running <= 0) { + callback(null); + callback = noop; + return; } - while (running < limit && started < size && !errored) { - started += 1; + while (running < limit && !errored) { + var key = nextKey(); + if (key === null) { + done = true; + if (running <= 0) { + callback(null); + callback = noop; + } + return; + } running += 1; - var key = keys[started - 1]; iterator(obj[key], key, function (err) { + running -= 1; if (err) { callback(err); errored = true; callback = noop; } else { - completed += 1; - running -= 1; - if (completed >= size) { - callback(null); - } - else { - replenish(); - } + replenish(); } }); }