async在node和浏览器里都可以用,API基本没区别
node环境:
1 2
| var async = require("async"); async.xxx();
|
浏览器环境:
1 2 3 4 5 6
| <script type="text/javascript" src="async.js"></script> <script type="text/javascript">
async.xxx();
</script>
|
本文总结下各API调用的方法。本文的示例代码在:AsyncExample
集合类
集合类的API
each
Array的迭代器方法,很常用
1 2 3 4 5 6 7 8 9 10 11
| async.each(["abc", "def", "ghi"], function(item, callback){
console.log(item); callback(null);// must call once
}, function(err){
if(err){ console.error("error"); } });
|
eachSeries
和each基本一样,但是顺序执行,API接口和参数都一样
eachLimit
也和each差不多,多出来的limit参数,是限制允许并发执行的任务数
1 2 3 4 5 6 7 8 9 10 11 12
| async.eachLimit(["123", "456", "789"], 2, function(item, callback){
console.log(item); callback();// 必须调用,才能触发下一个任务执行
}, function(error){
if(error){ console.error("error: " + error); }
});
|
map
将一个Array中的元素,按照一定的规则转换,得到一个新的数组(元素个数不变),也比较常用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| async.map([1,3,5], function(item, callback){
var transformed = item + 1; callback(null, transformed);
}, function(err, results){
if(err){ console.error("error: " + err); return; }
console.log(results);// [2, 4, 6]
});
|
mapSeries和mapLimit
基本差不多,就不多介绍了
filter
用于过滤Array中的元素
1 2 3 4 5 6 7 8 9
| async.filter([1, 5, 3, 7, 2], function(item, callback){
callback(item > 3);
}, function(results){
console.log(results);// [5, 7]
});
|
filterSeries
类似
reject和rejectSeries
和filter正好相反,filter是保留true的item,而reject是删除true的item
1 2 3 4 5 6 7 8 9
| async.reject([4, 7, 88, 11, 36], function(item, callback){
callback(item > 11);
}, function(results){
console.log(results);// [4, 7, 11]
});
|
reduce和reduceRight
将一个数组中的元素,归并成一个元素,看看就好了,用得不是很多,可以需要的时候再查
1 2 3 4 5 6 7 8 9 10 11 12 13
| async.reduce([3, 2, 1], 0, function(memo, item, callback){
callback(null, memo + item)
}, function(err, result){
if(err){ console.error("error: " + err); return; }
console.log(result);// 6 });
|
reduceRight差不多,只是Array中元素迭代的顺序是相反的:
1 2 3 4 5 6 7 8 9 10 11 12 13
| async.reduceRight(["!", "ld", "wor"], "hello ", function(memo, item, callback){
callback(null, memo + item)
}, function(err, result){
if(err){ console.error("error: " + err); return; }
console.log(result);// hello world! });
|
detect和detectSeries
从数组中找出符合条件的元素
这个API很像filter,参数也都一样,但是只会返回一个结果
1 2 3 4 5 6 7 8 9
| async.detect([13, 44, 23], function(item, callback){
callback(item > 37);
}, function(result){
console.log(result);// 44
});
|
sortBy
数组元素排序
1 2 3 4 5 6 7 8 9 10 11 12
| var person1 = {"name": "aaa", age:79}; var person2 = {"name": "bbb", age:23}; var person3 = {"name": "ccc", age:54};
async.sortBy([person1, person2, person3], function(person, callback){
callback(null, person.age);
}, function(err, sorted){
console.log(sorted); });
|
some
同名函数any。在数组中找至少一个元素,类似于filter和detect。区别在于,filter和detect是返回找到的元素,而some是返回bool
1 2 3 4 5 6 7 8 9
| async.some([1, 5, 9], function(item, callback){
callback(item > 10);
}, function(result){
console.log(result);// false
});
|
every
同名函数all。跟some相反,如果数组中所有元素都满足条件,则返回true,否则返回false
1 2 3 4 5 6 7 8 9
| async.every([1, 21, 23], function(item, callback){
callback(item > 10);
}, function(result){
console.log(result);// false
});
|
concat
对数组中的元素进行迭代操作,形成一个新数组
1 2 3 4 5 6 7 8 9
| async.concat([1, 2, 3], function(item, callback){
callback(null, [item+1, item+2]);
}, function(err, results){
console.log(results);// [2, 3, 3, 4, 4, 5];
});
|
流程控制类
流程控制类的API
series
一组函数顺序执行,这个API很常用。当一个步骤完成时,调用callback(),不传递参数;如果其中一个步骤出错,则调用callback(err),后续的步骤就不会继续执行。每个步骤执行的结果,会汇总到最终callback的results参数中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| async.series([function(callback){
console.log("first task"); callback(null, 1);
}, function(callback){
console.log("second task"); callback({message:"some error"}, 2);// callback with a error parameter
}, function(callback){
console.log("third task");// not called callback(null, 3);
}],function(error, results){
if(error){ console.error("error happend: " + error); } console.log(results);// [1, 2] });
|
parallel
基本上和series一样,包括API的参数,区别在于,series是顺序执行,而parallel是同时执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| async.parallel([function(callback){
callback(null, 1);
}, function(callback){
callback({message:"error"}, null);
}, function(callback){
callback(null, 3);
}], function(error, results){
if(error){ console.error(error.message); }
console.log(results);
});
|
whilst和until
重复执行一个函数,直到test function的值为false或true。类似的还有doWhilst和doUntil
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var count = 0;
async.whilst( function () { return count < 5; }, function (callback) { console.log("call once"); count++; setTimeout(callback, 1000); }, function (err) { if(err){ console.log("error: " + err); } console.log("whilst done"); } );
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var count3 = 0;
async.until(function(){
return (count3 > 5);
}, function(callback){
count3 ++; setTimeout(callback, 1000);
}, function(error){
console.log("until done"); count3 = 0;
});
|
forever
循环执行一个函数,直到抛出错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| async.forever(function(callback){
setTimeout(function(){ console.log("forever..."); console.log(flag); flag ++; if(flag > 5){ callback({message:"hehe"}); }else{ callback(); } }, 1000);
}, function(err){
// once this callback be called, the "forever" stops if(err){ console.error("there is an error"); }
});
|
waterfall
这个可能是async库中最重要的一个方法,可以解决callback嵌套的问题。上一个流程的执行结果,会传给下一个流程的参数。如果其中一个流程出错,则会中止后续流程的执行,直接调用最终的callback。否则最后一个流程的结果,会传递给最终callback
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| async.waterfall([function(callback){
callback(null, "kyfxbl", 29);
}, function(name, age, callback){
console.log(name);// kyfxbl console.log(age);// 29 callback(null, 10000, 200);
}, function(salary, bonus, callback){
console.log(salary);// 10000 console.log(bonus);// 200 callback(null, [1, 2, 3]);
}], function(err, results){
console.log(results);// [1, 2, 3]
});
|
compose
可以将几个function组合成function,这个方法不是很常用
1 2 3 4 5 6 7 8 9 10 11 12
| // f(g(h(n))) async.compose(function(n, callback){ setTimeout(function(){ callback(null, n + 1); }, 10); }, function(n, callback){ setTimeout(function(){ callback(null, n * 3); },10); })(4, function(err, result){ console.log("compose result: " + result);// 13 });
|
queue
创建一个执行任务的队列,类似oc中的NSOperationQueue,好像用得不多
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var q = async.queue(function(task, callback){
console.log("hello " + task.name); callback(null);
}, 3);
q.push({name:"kyfxbl"}, function(err){ console.log("done"); });
q.push({name:"liting"}, function(err){ console.log("finish"); })
|
nextTick
node里其实已经有nextTick方法,这个方法是为了统一node和浏览器环境的行为,在浏览器环境,实际调用的是setTimeout(func, 0)函数
1 2 3 4 5 6 7 8 9 10 11
| var order = [];
async.nextTick(function(){ order.push(222); });
order.push(111);
process.nextTick(function(){ console.log(order);// [111, 222] });
|
times
重复执行函数n次,并收集最终结果
1 2 3 4 5 6 7 8 9
| async.times(5, function(n, next){
console.log("n: " + n); next(null, n * 2);
}, function(err, results){
console.log(results);// [0, 2, 4, 6, 8] });
|