文章目录
基础方法
arrayEachIndex
function arrayEachIndex(array, iterator, createCallback) {
var index = -1;
var size = array.length;
if (iterator.length === 3) {
while (++index < size) {
iterator(array[index], index, createCallback(index));
}
} else {
while (++index < size) {
iterator(array[index], createCallback(index));
}
}
}
baseEachKey
- 兼容对象和数组两种便利方式
function baseEachKey(object, iterator, createCallback, keys) {
var key;
var index = -1;
var size = keys.length;
if (iterator.length === 3) {
while (++index < size) {
key = keys[index];
iterator(object[key], key, createCallback(key));
}
} else {
while (++index < size) {
key = keys[index];
iterator(object[key], createCallback(key));
}
}
}
symbolEachIndex
function symbolEachIndex(collection, iterator, createCallback) {
var item;
var index = 0;
var iter = collection[iteratorSymbol]();
if (iterator.length === 3) {
while ((item = iter.next()).done === false) {
iterator(item.value, index, createCallback(index++));
}
} else {
while ((item = iter.next()).done === false) {
iterator(item.value, createCallback(index++));
}
}
return index;
}
timeSync 一次执行多少个迭代器
- 限制执行次数
function timesSync(n, iterator) {
var index = -1;
while (++index < n) {
iterator(index);
}
}
异步遍历
map
- 不保证异步执行顺序,但会保证异步结果顺序
- 通过闭包保存当前遍历的索引,done时记录结果
var array = [1, 3, 2];
var iterator = function(num, done) {
setTimeout(function() {
done(null, num);
}, num * 10);
};
nac.map(array, iterator, function(err, res) {
console.log(res); // [1, 3, 2];
});
实现
const map = createMap(arrayEachIndex, baseEachIndex, symbolEachIndex, true);
function createMap(arrayEach, baseEach, symbolEach, useArray) {
var init, clone;
if (useArray) {
init = Array;
clone = createArray; // 数组浅拷贝
} else {
init = function() {
return {};
};
clone = objectClone; // 对象浅拷贝
}
return function(collection, iterator, callback) {
callback = callback || noop;
var size, keys, result;
var completed = 0;
if (isArray(collection)) {
size = collection.length;
result = init(size);// 创建数组
arrayEach(collection, iterator, createCallback);
} else if (!collection) {
} else if (iteratorSymbol && collection[iteratorSymbol]) {
// TODO: size could be changed
result = init(0);
size = symbolEach(collection, iterator, createCallback);
size && size === completed && callback(null, result);
} else if (typeof collection === obj) {
keys = nativeKeys(collection);// Object.keys()
size = keys.length;
result = init(size);
baseEach(collection, iterator, createCallback, keys);
}
if (!size) {
callback(null, init());
}
function createCallback(key) { //key是通过闭包保存的索引
return function done(err, res) {
if (key === null) {
throwError();
}
if (err) {
key = null;
callback = once(callback);
callback(err, clone(result));
return;
}
// 存储map每一次遍历结果
result[key] = res;
key = null;
if (++completed === size) {
callback(null, result);
}
};
}
};
}
mapSeries
- 保证异步串行调用顺序和返回数组结果顺序
- 在done的回调中执行下一个遍历任务
function mapSeries(collection, iterator, callback) {
callback = callback || noop;
var size, key, keys, iter, item, result, iterate;
var sync = false;
var completed = 0;
if (isArray(collection)) {
size = collection.length;
iterate = iterator.length === 3 ? arrayIteratorWithIndex : arrayIterator;
} else if (!collection) {
// iteratorSymbol = typeof Symbol === func && Symbol.iterator;
} else if (iteratorSymbol && collection[iteratorSymbol]) { // 迭代器遍历
size = Infinity;
result = [];
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, []);
}
result = result || Array(size);
iterate();
function arrayIterator() {
// 当completed==size后,iterator会被赋值成throwError,后续调用done进行报错
iterator(collection[completed], done);
}
function arrayIteratorWithIndex() {
iterator(collection[completed], completed, done);
}
function symbolIterator() {
item = iter.next();
// 当completed==size后,callback会被赋值成throwError,后续调用done进行报错
item.done ? callback(null, result) : iterator(item.value, done);
}
function symbolIteratorWithKey() {
item = iter.next();
item.done ? callback(null, result) : iterator(item.value, completed, done);
}
function objectIterator() {
iterator(collection[keys[completed]], done);
}
function objectIteratorWithKey() {
key = keys[completed];
iterator(collection[key], key, done);
}
function done(err, res) {
if (err) {
iterate = throwError;
callback = onlyOnce(callback);
callback(err, createArray(result));
return;
}
result[completed] = res;
if (++completed === size) {
iterate = throwError; // 避免后续调用
callback(null, result);
callback = throwError;// 避免后续调用
} else if (sync) {
nextTick(iterate);
} else {
sync = true;
iterate();
}
sync = false;
}
}
mapLimit
- 限制每一次异步请求的次数
- 原理:只需要限制第一次发起请求的次数,然后在每一次请求回调中调用后续请求,即可实现每一次请求数量小于n
基本使用
var order = [];
var array = [1, 5, 3, 4, 2];
var iterator = function(num, done) {
setTimeout(function() {
order.push(num);
done(null, num);
}, num * 10);
};
async.mapLimit(array, 2, iterator, function(err, res) {
console.log(res); // [1, 5, 3, 4, 2]
console.log(order); // [1, 3, 5, 2, 4]
});
实现
function mapLimit(collection, limit, iterator, callback) {
callback = callback || noop;
var size, index, key, keys, iter, item, result, 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;
result = [];
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, []);
}
result = result || Array(size);
// 限制单次迭代器执行个数
timesSync(limit > size ? size : limit, iterate);
function arrayIterator() {
index = started++;
if (index < size) {
iterator(collection[index], createCallback(index));
}
}
function arrayIteratorWithIndex() {
index = started++;
if (index < size) {
iterator(collection[index], index, createCallback(index));
}
}
function symbolIterator() {
item = iter.next();
if (item.done === false) {
iterator(item.value, createCallback(started++));
} else if (completed === started && iterator !== noop) {
iterator = noop;
callback(null, result);
}
}
function symbolIteratorWithKey() {
item = iter.next();
if (item.done === false) {
iterator(item.value, started, createCallback(started++));
} else if (completed === started && iterator !== noop) {
iterator = noop;
callback(null, result);
}
}
function objectIterator() {
index = started++;
if (index < size) {
iterator(collection[keys[index]], createCallback(index));
}
}
function objectIteratorWithKey() {
index = started++;
if (index < size) {
key = keys[index];
iterator(collection[key], key, createCallback(index));
}
}
// 闭包保存当前索引
function createCallback(index) {
return function(err, res) {
if (index === null) {
throwError();
}
if (err) {
index = null;
iterate = noop;
callback = once(callback);
callback(err, createArray(result));
return;
}
result[index] = res;
index = null;
if (++completed === size) {
iterate = throwError;
callback(null, result);
callback = throwError;
} else if (sync) {
nextTick(iterate);
} else {
sync = true;
iterate();
}
sync = false;
};
}
}