async模块在流程控制方面给我们带来了比较全面的解决办法
-
串行控制: series、waterfall、compose;
-
并行控制:
parallel、parallelLimit、queue;
- 循环控制:
whilst、doWhilst、until、doUntil、forever;
- 其他控制:
apply、applyEach、iterator、auto;
series(tasks,callback);
首先登场的是series函数,它的作用是串行执行,一个函数数组中的每个函数,每一个函数执行完成之后才能执行下一个函数,示例如下:
series函数的第一个参数可以是一个数组也可以是一个JSON对象,参数类型不同,影响的是返回数据的格式,如示例中的参数为数组,返回的results应该是这样的'[1,2]'。
var async = require('async');
async.series([
function(callback){
callback(null, 1);
},
function(callback){
callback(null, 2);
}
],function(err, results) {
console.log(results[0]);
});
waterfall(tasks, [callback])
waterfall和series函数有很多相似之处,都是按顺序依次执行一组函数,不同之处是waterfall每个函数产生的值,都将传给下一个函数,而series则没有这个功能,示例如下:
async.waterfall([
function(callback){
//task1
callback(null,1);
},function(data,callback){
//task1
callback(null,2);
}
],function(err,results){
console.log(results);
});
waterfall的tasks参数只能是数组类型
将示例中task1回调函数的第一个参数传入一个非空值,看一看输出的results的值
var async = require('async');
async.waterfall([ function(callback){
callback(null,1); },function(data,callback){
callback(null,2);
}
],function(err,results){ console.log(results);
});
results =2;
var async = require('async');
async.waterfall([
function(callback){
//task1
callback('test',1);
},function(data,callback){
//task1
callback(null,2);
}
],function(err,results){
console.log(results);
});
结果为:1,第二个function未执行
parallel(tasks, [callback])
parallel函数是并行执行多个函数,每个函数都是立即执行,不需要等待其它函数先执行。 传给最终callback的数组中的数据按照tasks中声明的顺序,而不是执行完成的顺序,示例如下:
async.parallel([
function(callback){
callback(null, 'one');
},
function(callback){
callback(null, 'two');
}
],
function(err, results){
});
tasks参数可以是一个数组或是json对象,和series函数一样,tasks参数类型不同,返回的results格式会不一样。
parallelLimit(tasks, limit, [callback])
parallelLimit函数和parallel类似,但是它多了一个参数limit。 limit参数限制任务只能同时并发一定数量,而不是无限制并发,示例如下:
async.parallelLimit([
function(callback){
callback(null, 'one');
},
function(callback){
callback(null, 'two');
}
],
2,
function(err, results){});
whilst(test, fn, callback)
相当于while,但其中的异步调用将在完成后才会进行下一次循环。当你需要循环异步的操作的时候,它可以帮助你。示例如下:
var count = 0;
async.whilst(
function () { return count < 5; },
function (callback) {
count++;
setTimeout(callback, 1000);
},
function (err) {
}
);
forever(fn, errback);
forever函数比较特殊,它的功能是无论条件如何,函数都一直循环执行,只有出现程序执行的过程中出现错误时循环才会停止,callback才会被调用。
async.forever(
function(next) {
},
function(err) {
}
compose(fn1, fn2...);
使用compose可以创建一个异步函数的集合函数,将传入的多个异步函数包含在其中,当我们执行这个集合函数时,会依次执行每一个异步函数,每个函数会消费上一次函数的返回值。
我们可以使用compose把异步函数f、g、h,组合成f(g(h()))的形式,通过callback得到返回值,请看示例:
var async = require('async');
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);
demo(4, function (err, result) {
if(err)
throw err;
console.log(result);});
//result =15
auto(tasks, [callback]);
用来处理有依赖关系的多个任务的执行。示例如下:
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) {
console.log('err = ', err);
console.log('results = ', results);
});
apply(function, arguments..)
apply是一个非常好用的函数,可以让我们给一个函数预绑定多个参数并生成一个可直接调用的新函数,简化代码。示例如下:
// using apply
async.parallel([
async.apply(fs.writeFile, 'testfile1', 'test1'),
async.apply(fs.writeFile, 'testfile2', 'test2'),
]);
// the same process without using apply
async.parallel([
function(callback){
fs.writeFile('testfile1', 'test1', callback);
},
function(callback){
fs.writeFile('testfile2', 'test2', callback);
}
]);
```
It's possible to pass any number of additional arguments when calling the
continuation:
```js
node> var fn = async.apply(sys.puts, 'one');
node> fn('two', 'three');
one
two
three
queue(worker, concurrency);
queue相当于一个加强版的parallel,主要是限制了worker数量,不再一次性全部执行。当worker数量不够用时,新加入的任务将会排队等候,直到有新的worker可用。
它有多个点可供回调,如无等候任务时(empty)、全部执行完时(drain)等。
示例:定义一个queue,其worker数量为2:
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');
});
当最后一个任务交给worker执行时,会调用empty函数:
q.empty = function() {
console.log('no more tasks wating');
}
iterator(tasks)
将一组函数包装成为一个iterator,可通过next()得到以下一个函数为起点的新的iterator。该函数通常由async在内部使用,但如果需要时,也可在我们的代码中使用它。
var iterator = async.iterator([
function(){ console.log('one'); },
function(){ console.log('two'); },
function(){ console.log('three'); }
]);
var iterator2 = iterator();
//'one'
var iterator3 = iterator2();
//'two'
iterator3();
//'three'
var nextfn = iterator2.next();
nextfn();
//'three'
```