Node.js 异步流程控制
异步流程控制对象async
- 串行无关联:async.series
- 并行无关联:async.parallel
- 串行有关联:waterfall
- parallelLimit:parallelLimit函数和parallel类似,但是他多了一个参数limit
- limit参数限制任务只能同时并发一定数量,而不是无限制并发
首先我们需要安装async模块:
我们来看看同步的情况:
function oneFun(){
console.log("oneFun");
}
function twoFun(){
console.log("twoFun");
}
oneFun();
twoFun();
console.log("end");
方法同步执行。
现在我们来写一个异步的例子:
function oneFun(){
var i = 0;
/*
setTimeout(function(){
console.log("oneFun");
},1000);//1秒之后调用
*/
setInterval(function(){
console.log("oneFun");
i++;
if(i == 3){
clearInterval(this);
}
},1000);//每隔1秒调用一次
}
function twoFun(){
var j = 0;
setInterval(function(){
console.log("twoFun");
j++;
if(j == 3){
clearInterval(this);
}
},1000);//每隔1秒调用一次
}
oneFun();
twoFun();
console.log("end");
我们发现两个方法交叉执行。
如果我们想要oneFun执行完在执行twoFun的话,我们需要如下改写代码:
function oneFun(){
var i = 0;
/*
setTimeout(function(){
console.log("oneFun");
},1000);//1秒之后调用
*/
setInterval(function(){
console.log("oneFun");
i++;
if(i == 3){
clearInterval(this);
twoFun();//等待oneFun执行完回调
}
},1000);//每隔1秒调用一次
}
function twoFun(){
var j = 0;
setInterval(function(){
console.log("twoFun");
j++;
if(j == 3){
clearInterval(this);
}
},1000);//每隔1秒调用一次
}
oneFun();
console.log("end");
我们发现实现了我们想要的,但是如果我们要执行的方法很多,就需要回调中继续嵌套回调,这样看起来很乱而且难以维护。
async.series
我们接下来用async.series来改造:
var async = require('async');
function exec(){
//串行无关联
async.series(
{ //这里面是串行的方法
one : function(done){
//回调函数写在这
done(null,'one完毕');//done执行完之后才会执行two函数
},
two : function(done){
done(null,'two完毕');
}
},function(err,rs){
console.log(err);
console.log(rs);
}
)
}
exec();
console.log("end");
var async = require('async');
function exec(){
//串行无关联
async.series(
{ //这里面是串行的方法
one : function(done){
//回调函数写在这
done('错误','one完毕');//只要done不执行就不会执行下一个函数
},
two : function(done){
done(null,'two完毕');
}
},function(err,rs){
console.log(err);
console.log(rs);
}
)
}
exec();
console.log("end");
所以出现错误之后,下一个函数two就不执行了。
var async = require('async');
function exec(){
//串行无关联
async.series(
{ //这里面是串行的方法
one : function(done){
//回调函数写在这
var i = 0;
/*
setTimeout(function(){
console.log("oneFun");
},1000);//1秒之后调用
*/
setInterval(function(){
console.log("oneFun");
i++;
if(i == 3){
clearInterval(this);
done(null,'one完毕');
}
},1000);//每隔1秒调用一次
},
two : function(done){
var j = 0;
setInterval(function(){
console.log("twoFun");
j++;
if(j == 3){
clearInterval(this);
done(null,'two完毕');
}
},1000);//每隔1秒调用一次
}
},function(err,rs){
console.log(err);
console.log(rs);
}
)
}
exec();
console.log("end");
我们可以看出oneFun执行完毕之后,two才开始执行
- series可以接受数组作为参数,需要串行处理的方法作为数组的元素。
var async = require('async');
async.series(
[
function (callback) {
setTimeout(function () {
console.log('event A occurs')
callback(null, 'A') // 第一个参数是异常错误,第二个参数是返回值
}, 3000)
},
function (callback) {
console.log('event B occurs');
callback(null, 'B')
}
], function (err, results) {
// results是返回值的数组
console.log('event ' + results[0] + results[1] + ' occurs')
}
)
console.log("event D occurs")
- async.series也可以接受对象作为参数,代码如下:
var async = require('async');
async.series(
{
A: function (callback) {
setTimeout(function () {
console.log('event A occurs')
callback(null, 'A') // 第一个参数是异常错误,第二个参数是返回值
}, 3000)
},
B: function (callback) {
console.log('event B occurs');
callback(null, 'B')
}
}, function (err, results) {
// results是所有的返回值合集,results.A获取的是A的返回值。
console.log('event ' + results.A + results.B + ' occurs')
}
)
console.log("event D occurs")
var async = require('async');
function exec(){
//串行无关联
async.series(
{ //这里面是串行的方法
one : function(done){
//回调函数写在这
var i = 0;
/*
setTimeout(function(){
console.log("oneFun");
},1000);//1秒之后调用
*/
setInterval(function(){
console.log("oneFun");
i++;
if(i == 3){
clearInterval(this);
done('错误','one完毕');
}
},1000);//每隔1秒调用一次
},
two : function(done){
var j = 0;
setInterval(function(){
console.log("twoFun");
j++;
if(j == 3){
clearInterval(this);
done(null,'two完毕');
}
},1000);//每隔1秒调用一次
}
},function(err,rs){
console.log(err);
console.log(rs);
}
)
}
exec();
console.log("end");
oneFun的done出现错误,所以被拦截了,所以twoFun就不会执行。
注意:如果任何一个方法在callback中返回了一个异常错误,停止后续方法的执行,且async.series的回调立即执行。
async.parallel
- async.parallel可以接受对象作为参数
var async = require('async');
function exec(){
//并行无关联
async.parallel(
{
one : function(done){
//回调函数写在这
var i = 0;
/*
setTimeout(function(){
console.log("oneFun");
},1000);//1秒之后调用
*/
setInterval(function(){
console.log("oneFun");
i++;
if(i == 3){
clearInterval(this);
done(null,'one完毕');
}
},1000);//每隔1秒调用一次
},
two : function(done){
var j = 0;
setInterval(function(){
console.log("twoFun");
j++;
if(j == 3){
clearInterval(this);
done(null,'two完毕');
}
},1000);//每隔1秒调用一次
}
},function(err,rs){
console.log(err);
console.log(rs);
}
)
}
exec();
console.log("end");
- async.parallel可以接受数组作为参数
var async = require('async');
async.parallel(
[
function (callback) {
setTimeout(function () {
console.log('event A occurs')
callback(null, 'A')
}, 3000)
},
function (callback) {
console.log('event B occurs')
callback(null, 'B')
}
], function (err, result) {
console.log("event C occurs")
console.log(result)
}
)
console.log("event D occurs")
var async = require('async');
function exec(){
//并行无关联
async.parallel(
{
one : function(done){
//回调函数写在这
var i = 0;
/*
setTimeout(function(){
console.log("oneFun");
},1000);//1秒之后调用
*/
setInterval(function(){
console.log("oneFun");
i++;
if(i == 3){
clearInterval(this);
done('错误','one完毕');
}
},1000);//每隔1秒调用一次
},
two : function(done){
var j = 0;
setInterval(function(){
console.log("twoFun");
j++;
if(j == 3){
clearInterval(this);
done(null,'two完毕');
}
},1000);//每隔1秒调用一次
}
},function(err,rs){
console.log(err);
console.log(rs);
}
)
}
exec();
console.log("end");
注意:
1、并行执行,所有任务执行完后,立即执行回调函数。
2、如果有一个任务执行异常报错,立即执行回调函数。
async.waterfall
waterfall:串行,前一个任务的结果传递给后一个任务。
var async = require('async');
function exec(){
async.waterfall(
[
function(done){
//回调函数写在这
var i = 0;
/*
setTimeout(function(){
console.log("oneFun");
},1000);//1秒之后调用
*/
setInterval(function(){
console.log("oneFun");
i++;
if(i == 3){
clearInterval(this);
done(null,'one完毕'); // 第一个参数是error,第二个参数是下一个任务的参数
}
},1000);//每隔1秒调用一次
},
function(preValue,done){
var j = 0;
setInterval(function(){
console.log("twoFun");
j++;
if(j == 3){
clearInterval(this);
done(null,preValue + ',two完毕');
}
},1000);//每隔1秒调用一次
}
],function(err,rs){
console.log(err);
console.log(rs);
}
)
}
exec();
console.log("end");
var async = require('async');
function exec(){
async.waterfall(
[
function(done){
//回调函数写在这
var i = 0;
/*
setTimeout(function(){
console.log("oneFun");
},1000);//1秒之后调用
*/
setInterval(function(){
console.log("oneFun");
i++;
if(i == 3){
clearInterval(this);
done(null,'one完毕');
}
},1000);//每隔1秒调用一次
},
function(preValue,done){
var j = 0;
setInterval(function(){
console.log(preValue + "twoFun");
j++;
if(j == 3){
clearInterval(this);
done(null,preValue + ',two完毕');
}
},1000);//每隔1秒调用一次
}
],function(err,rs){
console.log(err);
console.log(rs);
}
)
}
exec();
console.log("end");