Async库学习笔记
Async是个功能比较强大的异步流程控制库,常用的流程控制模式有串行,并行和瀑布流模式。注意和【async await】区分开。
1. Async串行控制
串行控制的函数为
function series(tasks, callback) {..}
参数tasks
为任务函数的数组,callback
为回调函数。且数组中每个函数都有一个包含两个参数[error & result]的回调函数。数组中所有的函数成功串行执行完毕或者出错都直接执行series的回调函数。
示例:
有三个函数串行执行,每个函数运行时间为1s,且出错概率为20%。出错直接抛出一个错误并进入最后的回调函数,不再执行后续的函数。
const async = require('async');
async.series([
function (callback) {
setTimeout(function () {
if (Math.random() < 0.2) {
callback(new Error(), 'f1 error');
} else {
console.log('1 over');
callback(null, new Date().toLocaleString());
}
}, 1000);
},
function (callback) {
setTimeout(function () {
if (Math.random() < 0.2) {
callback(new Error(), 'f2 error');
} else {
console.log('2 over');
callback(null, new Date().toLocaleString());
}
}, 1000);
},
function (callback) {
setTimeout(function () {
if (Math.random() < 0.2) {
callback(new Error(), 'f3 error');
} else {
console.log('3 over');
callback(null, new Date().toLocaleString());
}
}, 1000);
}
], function (error, results) {
if (error) {
console.log('error: ');
console.log(results);
} else {
console.log('time: ', results);
}
});
输出可能的结果为
Output1 三个函数都没出错·:
1 over
2 over
3 over
time: [ '2019-11-9 16:54:02', '2019-11-9 16:54:03', '2019-11-9 16:54:04' ]
Output2 第二个函数出错了:
1 over
error:
[ '2019-11-9 16:54:18', 'f2 error' ]
1.1 Promise实现的串行控制
下面用链式的Promise来实现上述串行控制,唯一不同的一点是async.series函数回调函数可以获取所有程序的返回结果,链式Promise最后只能获取到一个resolve的结果,不过可以通过别的方法实现。
new Promise(function (resolve, reject) {
setTimeout(function () {
if (Math.random() < 0.2) {
reject('f1 error');
} else {
console.log('1 over');
resolve(new Date().toLocaleString());
}
}, 1000);
}).then(function () {
return new Promise(function(resolve, reject){
setTimeout(function () {
if (Math.random() < 0.2) {
reject('f2 error');
} else {
console.log('2 over');
resolve(new Date().toLocaleString());
}
}, 1000);
})
}).then(function () {
return new Promise(function(resolve, reject){
setTimeout(function () {
if (Math.random() < 0.2) {
reject('f3 error');
} else {
console.log('3 over');
resolve(new Date().toLocaleString());
}
}, 1000);
})
}).then(function (results) {
console.log('time: ', results);
}).catch(function (error) {
console.log('error: ');
console.log(error);
});
2. Async瀑布模式控制
上面介绍是串行控制,且各个函数之间没有数据交互。如果前面一个函数作为后一个函数的输入参数的话就要用到瀑布流控制函数。瀑布流函数为:
function waterfall(tasks, callback) {..}
示例:
和上面例子相似,有三个数串行执行,每个函数运行时间为1s,且出错概率为20%。前一个函数的回调函数中的数据传给下一个函数作为参数。
const async = require('async');
async.waterfall([
function (callback) {
console.log("I am f1");
if (Math.random() < 0.2) {
callback(new Error(), 'f1 error');
} else {
callback(null, 'res-1');
}
},
function (data, callback) {
console.log("I am f2");
console.log('get data', data);
if (Math.random() < 0.2) {
callback(new Error(), 'f2 error');
} else {
callback(null, 'res-2');
}
},
function (data, callback) {
console.log("I am f3");
console.log('get data', data);
if (Math.random() < 0.2) {
callback(new Error(), 'f3 error');
} else {
callback(null, 'res-3');
}
}], function (error, result) {
if (error) {
console.log('error: ', result);
} else {
console.log('result: ', result);
}
});
和上面例子一样是串行执行的,所以就不加延时函数了。函数数组除了第一个函数只有一个参数,后面的函数都有两个参数,且第一个参数为上一个函数的callback中的第二个数据。
输出
Output1 无错误时:
I am f1
I am f2
get data res-1
I am f3
get data res-2
result: res-3
可以看出函数2的参数data即为函数1的回调返回值。
Output 2 函数2出错时:
I am f1
I am f2
get data res-1
error: f2 error
2.1 Promise 实现的瀑布模式控制
这个和上一个类似,貌似很easy。只需要在后面的then函数里面加个参数就能收到上一个函数的结果了。同样是出错直接进入catch。
new Promise(function (resolve, reject) {
console.log('I am f1');
if (Math.random() < 0.2) {
reject('f1 error');
} else {
resolve('res-1');
}
}).then(function (data) {
return new Promise(function (resolve, reject) {
console.log("I am f2");
console.log('get data', data);
if (Math.random() < 0.2) {
reject('f2 error');
} else {
resolve('res-2');
}
})
}).then(function (data) {
return new Promise(function(resolve, reject){
console.log("I am f3");
console.log('get data', data);
if (Math.random() < 0.2) {
reject('f3 error');
} else {
resolve('res-3');
}
})
}).then(function (results) {
console.log('time: ', results);
}).catch(function (error) {
console.log('error: ');
console.log(error);
});
Async 并行控制
这个并行控制的函数和js资审异步机制差不多,几个函数都是同时运行的。有点类似Promise.all,几个函数同时运行,没有错误执行相应的操作,有错误则报错。直接看例子。
示例:
const async = require('async');
async.parallel([
function (callback) {
setTimeout(function () {
callback(null, 'first ' + new Date().toLocaleString());
}, 2000);
},
function (callback) {
setTimeout(function () {
callback(null, 'second ' + new Date().toLocaleString());
}, 1000);
}],
function (error, results) {
console.log(error);
console.log(results);
});
输出:
null
[ 'first 2019-11-9 21:16:08', 'second 2019-11-9 21:16:07' ]
可以看出第二个函数先调用的回调函数,这个和Promise.all差不多。
3.1 Promise 实现并行控制
前面也说了和Promise.all类似,就写个类似的栗子吧。
let fun1 = new Promise(function (resolve, reject) {
setTimeout(function () {
if (Math.random() < 0.2) {
console.log('I am f1');
reject('f1 error');
} else {
resolve(new Date().toLocaleString());
}
}, 2000)
});
let fun2 = new Promise(function (resolve, reject) {
setTimeout(function () {
if (Math.random() < 0.2) {
console.log("I am f2");
reject('f2 error');
} else {
resolve(new Date().toLocaleString());
}
}, 1000);
});
let fun3 = new Promise(function (resolve, reject) {
setTimeout(function () {
if (Math.random() < 0.2) {
console.log("I am f3");
reject('f3 error');
} else {
resolve(new Date().toLocaleString());
}
}, 1000);
});
Promise.all([fun1, fun2, fun3]).then(function (results) {
console.log('success: ', results); //返回三个函数的resolve内容
}).catch(function (error) {
console.log('error:', error);
});
总结
研究了小半天突然发现这个Async并没啥卵用啊,起码这3个简单的函数的功能,Promise都可以实现。唯一好处就是看着更简洁一些。不过话说回来,简洁也是一大优点。。Promise链式调用与层层嵌套的回调相比也就是看着简洁。刚入门Node.js,记录一下作学习笔记。