Async 异步流程控制
Async是node.js流程控制工具包,提供了直接而强大的异步功能。基于Javascript为Node.js设计,同时也可以直接在浏览器中使用。
Async提供了大约20个函数,包括常用的 map, reduce, filter, forEach 等,异步流程控制模式包括,串行(series),并行(parallel),瀑布(waterfall)等。
async主要实现了三个部分的流程控制功能:
1. 集合: Collections
2. 流程控制: Control Flow
3. 工具类: Utils
下载安装
下载地址:https://github.com/caolan/async/blob/master/lib/async.js
可使用npm命令安装:
npm install async
在浏览器中安装:
bower install async
在浏览器中使用(支持IE6, IE7, IE8, FF3.6 and Chrome 5):
<script type="text/javascript" src="async.js"></script>
<script type="text/javascript">
async.map(data, asyncProcess, function(err, results){
alert(results);
});
</script>
集合
each
async.each [1,2,3], (item, done)->
console.log item
done
, (err)->
console.log err
async.each [1,2,3], (item, callback)->
if item > 2
console.log item
callback
else
console.log item
callback
, (err)->
console.log err
obj = { dev: “myDev”, test: “myTest”}
configs = {}
async.forEachOf obj, (value, key, callback)->
console.log key
console.log value
Callback
, (err)->
Console.log err if err
和each不同的是,forEachOf 迭代的参数是一个对象,对象的key做为迭代器的第二个参数。
map
async.map [1,2,3], (item, callback)->
//对数组中的每一项item, 进行处理
callback null, item + 1 //返回
, (err, results)->
//得到结果集results
console.log results // 2,3,4
map与each的区别是,map关心结果,返回结果集results;each 不关心结果,不返回结果集。
filter
async.filter [1,2,3], (item, callback)->
callback item > 2 //按条件过滤数组,callback参数只能为true或false
,(results)->
console.log(results) //3
reject
async.reject[1,2,3], (item, callback)->
callback item > 2 // reject跟filter正好相反,当测试为true时则抛弃
,(results)->
console.log(results) //1,2
reduce
可以让我们给定一个初始值,用它与集合中的每一个元素做运算,最后得到一个值。reduce从左向右来遍历元素,如果想从右向左,可使用reduceRight
async.reduce [123], 1, (meno, item, callback)->
callback meno+item //初始值1与数组中的每一项之和
, (err, result)->
console.log result // 7
detect
用于取得集合中满足条件的第一个元素。它分为并行与顺序执行两种方式,分别对应函数detect和detectSeries
async.detect [1,2,3], (item, callback)->
callback item > 1
, (result)->
console.log result //2, 找到第一个大于1的数
sortBy
对集合内的元素进行排序,依据每个元素进行某异步操作后产生的值,从小到大排序。
async.sortBy [1,9,3,5], (item, callback)->
callback null, item //从小到大排序
, (err, result) ->
console.log result
async.sortBy [1,9,3,5], (item, callback)->
callback null, item*-1 //从大到小排序
, (err, result) ->
console.log result
async.sortBy objs, (obj, callback)->
callback null, obj.update//按对象的update字段(修改时间)从小到大排序
, (err, result) ->
console.log result
some
当集合中是否有至少一个元素满足条件时,最终callback得到的值为true,否则为false
async.some [1,2,3], (item, callback)->
callback item > 2
, (err, result)->
console.log result //true
every
如果集合里每一个元素都满足条件,则传给最终回调的result为true,否则为false
async.every [1,2,3], (item, callback)->
callback item > 2
, (err, result)->
console.log result // false
concat
将多个异步操作的结果合并为一个数组
data = { aaa: [11,22,33], bbb: [44,55], ccc: 66 } keys = [ {name: 'aaa'}, {name: 'bbb'}, {name: 'ccc'} ] async.concat keys, (key, callback)-> callback null , data[key.name] , (err, result)-> console.log JSON.stringify result //[11,22,33,44,55,66]
流控制Control Flow
series
串行执行,一个函数数组中,每一个函数执行完成之后才能执行下一个函数。
async.series [ (callback)-> callback null, "function1" (callback)-> callback null, "function2" ], (err, result)-> console.log JSON.stringify result //["function1","function2"]
async.series [ one:(callback)-> callback null, "function1" two:(callback)-> callback null, "function2" ], (err, result)-> console.log JSON.stringify result //{one:"function1", two:"function2"}
parallel
并行执行多个函数,每个函数都是立即执行,不需要等待其它函数先执行。传给最终callback的数组中的数据按照tasks中声明的顺序,而不是执行完成的顺序。
async.parallel [
(callback)->
callback null, “one”
(callback)->
callback null, “two”
], (err, results)->
console.log results // [“one”,”two”]
async.parallel [
one:(callback)->
callback null, 1
two:(callback)->
callback null, 2
], (err, results)->
console.log results // {one:1, two:2}
auto
执行多个函数,根据实际情况选择是串行执行还是并行执行
//前两个函数并行执行,后两个函数串行执行
async.auto {
//获取数据data
get_data: (callback)->
console.log “in get_data”
callback null, data, “converted to array”
//创建目录
make_folder: (callback)->
console.log “in make_folder”
callback null, “folder”
//get_data,make_folder并行执行,执行完成后将获取的数据写入文件并保存在创建的目录中
write_file: [“get_data”, “make_folder”, (callback, results)->
console.log (“in write_file”, JSON.stringify results)
callback null, “filename”
],
//write_file执行完成后,发送邮件
email_link: [“write_file”, (callback, results)->
console.log “in email_link”, JSON.stringify(results)
callback null,{file: results.write_file, email:”[email protected]"}
]
}, (err, results)->
console.log results
waterfall
按顺序依次执行一组函数。每个函数产生的值,都将传给下一个。
async.waterfall [ (callback)-> callback null, "one", "two" (arg1, arg2, callback)-> console.log "====#{arg1}====#{arg2}" //====one====two callback null, "three" (arg1, callback)-> console.log "===="+arg1 //====three callback null, "done" ], (err, result)-> console.log result //done
compose
创建一个包括一组异步函数的函数集合,每个函数会消费上一次函数的返回值。
add1 = (n, callback) -> callback null, n+1 mul3 = (n, callback)-> callback null, n*3 add1-mul3 = async.compose(mul3, add1) //从右到左调用函数 add1-mul3 4, (err, result)-> console.log result //15
whilst
相当于while,但其中的异步调用将在完成后才会进行下一次循环。
count = 0
async.whilst(
//条件 -> return count < 5 //true,则第二个函数会继续执行,否则,调出循环
//循环的主体 (callback)-> console.log "=========count:#{count}" count++ callback()
//如果条件不满足,或者发生异常 (err)-> console.log err if err )
dowhilst
相当于do…while, doWhilst交换了fn,test的参数位置,先执行一次循环,再做test判断。
count = 0
async.whilst(
//循环的主体 (callback)-> console.log "=========count:#{count}" count++ callback()
//条件 -> return count < 5 //true,则第二个函数会继续执行,否则,调出循环
//如果条件不满足,或者发生异常 (err)-> console.log err if err )
until
until与whilst正好相反,当test为false时循环,与true时跳出。其它特性一致。
doUntil
doUntil与doWhilst正好相反,当test为false时循环,与true时跳出。其它特性一致。
forever
无论条件循环执行,如果不出错,callback永远不被执行。
count = 0
async.forever(
(next)->
console.log "=========count:#{count++}"
next()
(err)->
console.log err if err
)
retry
发生错误时,重复执行指定次数,执行成功则停止执行
myMethod = (callback)-> console.log "============hello" callback "err" //myMethod方法返回错误,所以会重复执行5次;如果callback没有错误,则只执行一次
async.retry(5, myMethod, (err, result)->
console.log "err:"+err
console.log "result:"+result
)
apply
apply是一个非常好用的函数,可以让我们给一个函数预绑定多个参数并生成一个可直接调用的新函数,简化代码。
function(callback) { t.inc(3, callback); }
//等价于
async.apply(t.inc, 3);
async.parallel [
async.apply(t.inc, 3),
async.apply(t.fire, 100)
], (err, results)->
console.log “JSON.stringify results”
nextTick
与nodejs的nextTick一样,再最后调用函数
call_order = []
async.nextTick( ()->
call_order.push(“two”)
)
call_order.push(“one”)
console.log call_order //[“one”,”two”]
times
异步运行,可以指定调用几次,并把结果合并到数组中返回
async.times 5, (parm, next)->
createUser parm, (err, user)->
next err, user
, (err, users)->
//得到5个user
memoize
让某一个函数在内存中缓存它的计算结果。对于相同的参数,只计算一次,下次就直接拿到之前算好的结果。
unmemoize
让已经被缓存的函数,返回不缓存的函数引用。
参考文献
https://www.npmjs.com/package/async
http://blog.fens.me/nodejs-async/