node的异步io虽然好用,但是控制异步流程确实一个比较麻烦的事情,比如在爬虫中控制并发数量,避免并发过大导致网站宕机或被加入黑名单。因此需要一个工具来控制并发,这个工具可以自己写或者使用async(官方文档点击这里)。代码基于node 8.x,如版本过低可能会出现错误。
async本身有七十多个方法,这里只说明几个比较常用的简单函数用法,想进一步学习可参考文档。总的来说分为两大类。
tasks为函数数组,数组中的每一项都为待执行函数。
1 const asyncx = require( 'async' );
2
3 let tasks = [];
4 for( let i = 0 ; i < 10 ; i++ )
5 {
6 tasks.push(
7 function( callback ){
8 //dosomething
9 console.log( i );
10 //本函数用来通知async本次任务完成情况,并把结果带出去。
11 callback( null , i ); //第一个参数为异常参数,如果传入一个error( 比如new Error('error') ),并发结束,调用series里的回调。
12 }
13 )
14 }
15 asyncx.series( tasks , function(err , res ){
16 if( err )
17 console.log( err );
18 console.log( res );
19 } )
运行结果
如果待处理的函数也是异步函数可将callback参数传入到异步函数中,在真正结束的时候调用callback。
1 const asyncx = require( 'async' ); //模块命名为asyncx避免和es7中的async/await冲突
2
3 let tasks = [];
4 for( let i = 0 ; i < 10 ; i++ )
5 {
6 tasks.push(
7 function( callback ){
8 setTimeout( function(){
9 console.log(i);
10 callback( null , 1 ); //在这里整个处理才是真正完成,然后调用callback通知async本任务结束
11 } , 2000 );
12 }
13 )
14 }
15 asyncx.series( tasks , function(err , res ){
16 if( err )
17 console.log( err );
18 console.log( res );
19 } )
如果想要在任务中使用es7的async/await 可将待处理代码放在一个闭包中(直接在function前加async会报错),下面示例。
1 const asyncx = require( 'async' ); //模块命名为asyncx避免和es7中的async/await冲突
2
3 let tasks = [];
4 for( let i = 0 ; i < 10 ; i++ )
5 {
6 tasks.push(
7 function( callback ){
8 (async function(){
9 let sum = await doSomething( i );
10 callback( null , sum );
11 })();
12 }
13 )
14 }
15
16 async function doSomething( i ){
17 return new Promise( function( resolve , reject ){
18 setTimeout(function(){
19 console.log( i );
20 resolve( i );
21 } , 1000 );
22 } );
23 }
24
25 asyncx.series( tasks , function(err , res ){
26 if( err )
27 console.log( err );
28 console.log( res );
29 } )
参数如上,不限制并发
参数同上,num为最大并发数量
比如
async.map(['file1','file2','file3'], function(item,callback){
//dosomething
callback( null , 'done' );
}, function(err, results) {
// results is now an array of stats for each file
});
第二个参数为一个异步函数,要能接受两个参数item(前面集合中的一项),callback 通知async任务完成
还有其他的函数用法都是类似只是具体作用不一样。可参考官方文档说明。