安装: npm install –save async
引用: var async = require(‘async’);
series(tasks, callback)
串行执行task, 如果某个task报错, 后面的task将不会被执行
当tasks是函数数组, 执行顺序是按下标, 返回值(在callback参数中)也以数组的方式给出
当tasks是函数为属性值的对象, 执行顺序是代码编写顺序(注:但ECMAScript并没有规定必须在对象内记录属性顺序, 也就是说, 这时是执行顺序可能并不是代码编写的顺序, 如果对执行顺序比较敏感, 就应该使用数组的形式), 返回值(在callback参数中)也以对象的方式给出, 对象的字段名和值即对应了tasks对象中函数的执行结果
tasks 中的函数为 function(callback){}形式, callback函数用户输出task执行的结果, 参数1是错误信息, 参数2是task执行的结果
数组方式:
async.series([
function(callback){
callback(null, 1)
},
function(callback){
callback(null, 2)
}
], function(err, results){
console.log(results); // [1,2]
})
对象方式:
async.series({
one: function(callback){
callback(null, 1);
},
two: function(callback){
callback(null, 2);
}
},function(err, results) {
console.log(results); // {one:1,two:2}
});
waterfall(tasks, [callback])
串行执行tasks, 并且后一个task能拿到前一个task的执行结果
tasks只能是函数数组, 不能是对象
最后的执行结果为最后一个task的callback给的值
如果中间一个task出错, 后续task将不会执行, 最后拿到的错误信息和结果就是这个出错的task的callback给的值
async.waterfall([
function(callback){
callback(null,1); // task1 执行完成, 如果callback('error', 1), 后续task不会执行, 直接触发 结果函数的调用
},function(data,callback){
callback(null,2 +data); // 可以从data中拿到 task1的结果
}
],function(err,result){ // 结果函数, result 为最后一个执行的task的给出的结果
console.log(result);
});
parallel(tasks, [callback])
并行执行tasks, 后一个task不会等待前一个task执行完成
tasks可以是函数数组, 也可以是对象
错误机制: 当某一个task报错时(Js毕竟是串行的), 会立即调用结果函数, 参数results中是已经执行完的结果, 并且结果函数不会再被调用
async.parallel([
function(callback){
setTimeout(function(){
callback(null, 'one')
}, 1000)
},
function(callback){
setTimeout(function(){
callback(null, 'two')
}, 1000)
}
],function(err, results){
console.log(results); // 1000后就会有结果
})
如果希望始终都执行完所有的task, 并了解其是否有error, 可以使用 reflect 包装一下task函数
async.parallel([
async.reflect(function(callback) {
// do some stuff ...
callback(null, 'one');
}),
async.reflect(function(callback) {
// do some more stuff but error ...
callback('bad stuff happened');
}),
async.reflect(function(callback) {
// do some more stuff ...
callback(null, 'two');
})
],
// optional callback
function(err, results) {
// values
// results[0].value = 'one'; // 注: 这里的结果在value字段中, 错误在error字段中
// results[1].error = 'bad stuff happened'
// results[2].value = 'two'
});
parallelLimit(tasks, limit, [callback])
并行执行task, 但同时并发数量控制在最多limit个
async.parallelLimit([
function(callback){
setTimeout(function(){
callback(null, 1)
}, 1000)
},
function(callback){
setTimeout(function(){
callback(null, 2)
},1000)
}
], 1, // 强制并发一个
function(err, results){
console.log(results) // 需要等待两秒才会执行
})
whilst(test, fn, callback)
与js中的while相似, 判断test返回值, 决定是否执行 fn, 直到 test 返回 false, 再执行 callback
fn的为 function(callback){}, 当fn的任务结束时, 就(异步)执行 callback, 注: 这里的重点是 fn 中能异步执行 callback, 表示任务结束
var list = [{name:'Jack',age:20},{name:'Lucy',age:18}];
var i = 0;
async.whilst(function(){
console.log(i)
return i<list.length
}, function(callback){
setTimeout(function(){
list[i++].age++
callback(null, i)
}, 1000)
}, function(err, n){ // 注: 这里n的值实际上是 undefined, 与文档中的不一致, 不知为何
console.log(list);
})
doWhilst(fn, test, callback)
与 whilst 类似, 不同的是 先执行一次 fn, 再判断 test 结果
until(test, fn, callback)
until与whilst正好相反,当test条件函数返回值为false时继续循环,与true时跳出
doUntil(fn, test, callback)
doUntil与doWhilst正好相反,当test为false时循环,与true时跳出
forever(fn, errback);
forever函数比较特殊,它的功能是无论条件如何,函数都一直循环执行,只有出现程序执行的过程中出现错误时循环才会停止,callback才会被调用。
compose(fn1, fn2…);
我理解与waterfall效果类似, 但它是用于创建函数的, 它可以创建一个异步函数的集合函数,将传入的多个异步函数包含在其中,当我们执行这个集合函数时,会依次执行每一个异步函数,每个函数会消费上一次函数的返回值。
function fn1(n, callback) {
setTimeout(function () {
callback(null, n + 1);
}, 1000);
}
function fn2(n, callback) {
setTimeout(function () {
callback(null, n * 3);
}, 1000);
}
var demo = async.compose(fn2, fn1); // 创建了一个新函数, 调用它就等于调用了fn1和fn2这俩异步函数
demo(4, function (err, result) {
// 处理结果
});
auto(tasks, [callback]);
很有用的函数, 用于处理有依赖关系的异步任务
如: getData 和 makeFolder 可以同时并发启动, 等待它俩结束后才能调用 writeFile, 等writeFile结束后 最好才能执行 emailLink
async.auto({
getData: function(callback){
callback(null, 'data', 'converted to array');
},
makeFolder: function(callback){
callback(null, 'folder');
},
writeFile: ['getData', 'makeFolder', function(callback, results){ // 需要在这里体现依赖项
callback(null, 'filename');
}],
emailLink: ['writeFile', function(callback, results){ // 需要在这里体现依赖项
callback(null, {'file':results.writeFile, 'email':'user@example.com'});
}]
}, function(err, results) { // auto 会自动处理依赖关系, 执行完成后最终调用callback
console.log('err = ', err);
console.log('results = ', results);
});
queue(worker, concurrency);
以队列方式处理任务, 可以指定并发处理任务的个数
用法:
1. 创建队列, 这里的重点是设计任务处理函数, 和指定并发处理个数
2. enqueue, 将任务数据放入队列
3. 可以指定empty回调, 当最后一个任务开始执行前, 会调用
示例:
var q = async.queue(function(task, callback) {
console.log('worker is processing task: ', task.name);
callback(); // 表示任务处理完成
}, 2);
// 投递任务
q.push({name: 'foo'}, function (err) {
console.log('finished processing foo');
});
// 投递任务
q.push({name: 'bar'}, function (err) {
console.log('finished processing bar');
});
// 没有更多任务时回调
q.empty = function() {
console.log('no more tasks wating');
}
apply(function, arguments..)
apply是一个非常好用的函数,可以让我们给一个函数预绑定多个参数并生成一个可直接调用的新函数,简化代码。示例如下:
function(callback) {
test(3, callback);
};
用apply改写:
async.apply(test, 3);
iterator(tasks)
将一组函数包装成为一个iterator,可通过next()得到以下一个函数为起点的新的iterator。该函数通常由async在内部使用,但如果需要时,也可在我们的代码中使用它。
var iter = async.iterator([
function() { console.log('111') },
function() { console.log('222') },
function() { console.log('333') }
]);
iter();
直接调用(),会执行当前函数,并返回一个由下个函数为起点的新的iterator。调用next(),不会执行当前函数,直接返回由下个函数为起点的新iterator。
对于同一个iterator,多次调用next(),不会影响自己。如果只剩下一个元素,调用next()会返回null。
参考:
http://cw.hubwiz.com/card/c/543e1a4f032c7816c0d5dfa1/1/1/1/