基础方法
异步遍历
reduce
基本使用
- 通过done将参数传递给下一个时才会执行下一次的迭代器
var collection = [1, 3, 2, 4];
var iterator = function(result, num, done) {
setTimeout(function() {
done(null, result + num);
}, num * 10);
};
async.reduce(collection, 5, iterator, function(err, res) {
console.log(res); // 15
});
实现
function reduce(collection, result, iterator, callback) {
callback = onlyOnce(callback || noop);
var size, key, keys, iter, item, iterate;
var sync = false;
var completed = 0;
if (isArray(collection)) {
size = collection.length;
iterate = iterator.length === 4 ? arrayIteratorWithIndex : arrayIterator;
} else if (!collection) {
} else if (iteratorSymbol && collection[iteratorSymbol]) {
size = Infinity;
iter = collection[iteratorSymbol]();
iterate = iterator.length === 4 ? symbolIteratorWithKey : symbolIterator;
} else if (typeof collection === obj) {
keys = nativeKeys(collection);
size = keys.length;
iterate = iterator.length === 4 ? objectIteratorWithKey : objectIterator;
}
if (!size) {
return callback(null, result);
}
iterate(result);
function arrayIterator(result) {
iterator(result, collection[completed], done);
}
function arrayIteratorWithIndex(result) {
// results value key next
iterator(result, collection[completed], completed, done);
}
function symbolIterator(result) {
item = iter.next();
item.done ? callback(null, result) : iterator(result, item.value, done);
}
function symbolIteratorWithKey(result) {
item = iter.next();
item.done ? callback(null, result) : iterator(result, item.value, completed, done);
}
function objectIterator(result) {
iterator(result, collection[keys[completed]], done);
}
function objectIteratorWithKey(result) {
key = keys[completed];
iterator(result, collection[key], key, done);
}
function done(err, result) { // 通过 done 传递result
if (err) {
callback(err, result);
} else if (++completed === size) {
iterator = throwError;
callback(null, result);
} else if (sync) { // 避免大量的同步任务阻塞时间循环,所以变成异步任务
nextTick(function() {
iterate(result);
});
} else {
sync = true;
iterate(result);
}
sync = false;
}
}
reduceRight
- reduceRight,从集合最后一位开始遍历
function reduceRight(collection, result, iterator, callback) {
callback = onlyOnce(callback || noop);
var resIndex, index, key, keys, iter, item, col, iterate;
var sync = false;
if (isArray(collection)) {
resIndex = collection.length; //从数组最后一位开始
iterate = iterator.length === 4 ? arrayIteratorWithIndex : arrayIterator;
} else if (!collection) {
} else if (iteratorSymbol && collection[iteratorSymbol]) {
// 对于symbol类型,先求出所有的值,再根据索引逆序
col = [];
iter = collection[iteratorSymbol]();
index = -1;
while ((item = iter.next()).done === false) {
col[++index] = item.value;
}
collection = col;
resIndex = col.length;
iterate = iterator.length === 4 ? arrayIteratorWithIndex : arrayIterator;
} else if (typeof collection === obj) {
keys = nativeKeys(collection);
resIndex = keys.length;
iterate = iterator.length === 4 ? objectIteratorWithKey : objectIterator;
}
if (!resIndex) {
return callback(null, result);
}
iterate(result);
function arrayIterator(result) {
iterator(result, collection[--resIndex], done);
}
function arrayIteratorWithIndex(result) {
iterator(result, collection[--resIndex], resIndex, done);
}
function objectIterator(result) {
iterator(result, collection[keys[--resIndex]], done);
}
function objectIteratorWithKey(result) {
key = keys[--resIndex];
iterator(result, collection[key], key, done);
}
function done(err, result) {
if (err) {
callback(err, result);
} else if (resIndex === 0) {
iterate = throwError;
callback(null, result);
} else if (sync) {
nextTick(function() {
iterate(result);
});
} else {
sync = true;
iterate(result);
}
sync = false;
}
}
compose
- 和普通reduce的区别是:传入迭代器的是方法,需要执行并传递result
基本使用
function add1(n, callback) {
setTimeout(function () {
callback(null, n + 1);
}, 10);
}
function mul3(n, callback) {
setTimeout(function () {
callback(null, n * 3);
}, 10);
}
var add1mul3 = nac.compose(mul3, add1); //mul3(add1(4))
add1mul3(4, function (err, result) {
// result now equals 15
console.log(result) // 15
});
实现:
function compose() {
// 参数进行了翻转
return seq.apply(null, reverse(arguments));
}
/**
* @memberof async
* @namespace seq
*/
function seq(/* functions... */) {
// fns:[add1,mul3]
var fns = createArray(arguments);
return function() {
var self = this
// args:[4,callback]
var args = createArray(arguments);
var callback = args[args.length - 1];
if (typeof callback === func) {
args.pop();
} else {
callback = noop;
}
reduce(fns, args, iterator, done);
function iterator(newargs, fn, callback) { // 这里的 callback 为 reduce 里的 done,会调用下一个任务或者最终回调
// 第一次:newargs:[4]、fn:add1
// 第二次:newargs:[5]、fn:mul3
var func = function(err) { //任务中调用的callback
// 第一次:nextargs:4+1=5
// 第二次:nextargs:5*3=15
var nextargs = slice(arguments, 1);// 将要传递给下一个任务的参数合并成一个,这也是不直接将callback传递的原因
callback(err, nextargs);
};
// 第一次:newargs:[4,func]
// 第二次:newargs:[5,func]
newargs.push(func); //push的作用是把callback传入
// 第一次:add1(4,func)
// 第二次:mul3(5,func)
fn.apply(self, newargs);
}
function done(err, res) {
// [15]
res = isArray(res) ? res : [res];
res.unshift(err);
callback.apply(self, res);
}
};
}