function arrayEachValue(array, iterator, createCallback) {
var value;
var index = -1;
var size = array.length;
if (iterator.length === 3) {
while (++index < size) {
value = array[index];
iterator(value, index, createCallback(value));
}
} else {
while (++index < size) {
value = array[index];
iterator(value, createCallback(value));
}
}
}
function baseEachValue(object, iterator, createCallback, keys) {
var key, value;
var index = -1;
var size = keys.length;
if (iterator.length === 3) {
while (++index < size) {
key = keys[index];
value = object[key];
iterator(value, key, createCallback(value));
}
} else {
while (++index < size) {
value = object[keys[index]];
iterator(value, createCallback(value));
}
}
}
function symbolEachValue(collection, iterator, createCallback) {
var value, item;
var index = 0;
var iter = collection[iteratorSymbol]();
if (iterator.length === 3) {
while ((item = iter.next()).done === false) {
value = item.value;
iterator(value, index++, createCallback(value));
}
} else {
while ((item = iter.next()).done === false) {
index++;
value = item.value;
iterator(value, createCallback(value));
}
}
return index;
}
function once(func) {
return function(err, res) {
var fn = func;
func = noop;
fn(err, res);
};
}
function timesSync(n, iterator) {
var index = -1;
while (++index < n) {
iterator(index);
}
}
基本使用:
var array = [1, 3, 2];
var iterator = function(num, done) {
setTimeout(function() {
order.push(num);
done(null, num==1);
}, num * 10);
};
nac.detect(array, iterator, function(err, res) {
console.log(res); // 1
console.log(order); // [1] ,在这一刻触发回调时,order数组的内容
setTimeout(()=>{
console.log(order) // [1,2,3]
},4000)
});
实现:
const detect = createDetect(arrayEachValue, baseEachValue, symbolEachValue, true);
function createDetect(arrayEach, baseEach, symbolEach, bool) {
return function(collection, iterator, callback) {
callback = callback || noop;
var size, keys;
var completed = 0;
// 区分不同类型的遍历
if (isArray(collection)) {
size = collection.length;
arrayEach(collection, iterator, createCallback); // createCallback会闭包保存当前遍历的值
} else if (!collection) {
} else if (iteratorSymbol && collection[iteratorSymbol]) { // var iteratorSymbol = typeof Symbol === func && Symbol.iterator;
size = symbolEach(collection, iterator, createCallback);
size && size === completed && callback(null);
} else if (typeof collection === obj) {
keys = nativeKeys(collection); // Object.keys
size = keys.length;
baseEach(collection, iterator, createCallback, keys);
}
if (!size) {
callback(null);
}
function createCallback(value) { // value为闭包保存的遍历元素
var called = false;
return function done(err, res) {
if (called) {
throwError();
}
called = true;
if (err) {
callback = once(callback);//只触发一次
callback(err);
} else if (!!res === bool) { //当返回值为true时
callback = once(callback);
callback(null, value);
} else if (++completed === size) {
callback(null);
}
};
}
}
}
var detectLimit = createDetectLimit(true);
function createDetectLimit(bool) {
return function(collection, limit, iterator, callback) {
callback = callback || noop;
var size, index, key, value, keys, iter, item, iterate;
var sync = false;
var started = 0;
var completed = 0;
if (isArray(collection)) {
size = collection.length;
iterate = iterator.length === 3 ? arrayIteratorWithIndex : arrayIterator;
} else if (!collection) {
} else if (iteratorSymbol && collection[iteratorSymbol]) {
size = Infinity;
iter = collection[iteratorSymbol]();
iterate = iterator.length === 3 ? symbolIteratorWithKey : symbolIterator;
} else if (typeof collection === obj) {
keys = nativeKeys(collection);
size = keys.length;
iterate = iterator.length === 3 ? objectIteratorWithKey : objectIterator;
}
if (!size || isNaN(limit) || limit < 1) {
return callback(null);
}
timesSync(limit > size ? size : limit, iterate);
function arrayIterator() {
index = started++;
if (index < size) {
value = collection[index];
iterator(value, createCallback(value));
}
}
function arrayIteratorWithIndex() {
index = started++;
if (index < size) {
value = collection[index];
iterator(value, index, createCallback(value));
}
}
function symbolIterator() {
item = iter.next();
if (item.done === false) {
started++;
value = item.value;
iterator(value, createCallback(value));
} else if (completed === started && iterator !== noop) {
iterator = noop;
callback(null);
}
}
function symbolIteratorWithKey() {
item = iter.next();
if (item.done === false) {
value = item.value;
iterator(value, started++, createCallback(value));
} else if (completed === started && iterator !== noop) {
iterator = noop;
callback(null);
}
}
function objectIterator() {
index = started++;
if (index < size) {
value = collection[keys[index]];
iterator(value, createCallback(value));
}
}
function objectIteratorWithKey() {
if (started < size) {
key = keys[started++];
value = collection[key];
iterator(value, key, createCallback(value));
}
}
function createCallback(value) {
var called = false;
return function(err, res) {
if (called) {
throwError();
}
called = true;
if (err) {
iterate = noop;
callback = once(callback);
callback(err);
} else if (!!res === bool) { // 返回true立即执行回调
iterate = noop;
callback = once(callback);
callback(null, value);
} else if (++completed === size) {
callback(null);
} else if (sync) {
nextTick(iterate);
} else {
sync = true;
iterate();
}
sync = false;
};
}
};
}
var detectSeries = createDetectSeries(true);
function createDetectSeries(bool) {
return function(collection, iterator, callback) {
callback = onlyOnce(callback || noop);
var size, key, value, keys, iter, item, iterate;
var sync = false;
var completed = 0;
if (isArray(collection)) {
size = collection.length;
iterate = iterator.length === 3 ? arrayIteratorWithIndex : arrayIterator;
} else if (!collection) {
} else if (iteratorSymbol && collection[iteratorSymbol]) {
size = Infinity;
iter = collection[iteratorSymbol]();
iterate = iterator.length === 3 ? symbolIteratorWithKey : symbolIterator;
} else if (typeof collection === obj) {
keys = nativeKeys(collection);
size = keys.length;
iterate = iterator.length === 3 ? objectIteratorWithKey : objectIterator;
}
if (!size) {
return callback(null);
}
iterate();
function arrayIterator() {
value = collection[completed];
iterator(value, done);
}
function arrayIteratorWithIndex() {
value = collection[completed];
iterator(value, completed, done);
}
function symbolIterator() {
item = iter.next();
value = item.value;
item.done ? callback(null) : iterator(value, done);
}
function symbolIteratorWithKey() {
item = iter.next();
value = item.value;
item.done ? callback(null) : iterator(value, completed, done);
}
function objectIterator() {
value = collection[keys[completed]];
iterator(value, done);
}
function objectIteratorWithKey() {
key = keys[completed];
value = collection[key];
iterator(value, key, done);
}
function done(err, res) {
if (err) {
callback(err);
} else if (!!res === bool) {
iterate = throwError;
callback(null, value);
} else if (++completed === size) {
iterate = throwError;
callback(null);
} else if (sync) {
nextTick(iterate);
} else {
sync = true;
iterate();
}
sync = false;
}
};
}
function createEvery(arrayEach, baseEach, symbolEach) {
var deny = createDetect(arrayEach, baseEach, symbolEach, false); // 注意最后一个参数是false,表明detect中为false时触发callback
return function every(collection, iterator, callback) {
callback = callback || noop;
deny(collection, iterator, done);
function done(err, res) {
if (err) {
return callback(err);
}
callback(null, !res);
}
};
}
function createEverySeries() {
var denySeries = createDetectSeries(false); // 注意传递的是false
return function everySeries(collection, iterator, callback) {
callback = callback || noop;
denySeries(collection, iterator, done);
function done(err, res) {
if (err) {
return callback(err);
}
callback(null, !res);
}
};
}
function createEveryLimit() {
var denyLimit = createDetectLimit(false); // 注意传递的是false
return function everyLimit(collection, limit, iterator, callback) {
callback = callback || noop;
denyLimit(collection, limit, iterator, done);
function done(err, res) {
if (err) {
return callback(err);
}
callback(null, !res);
}
};
}