【摘要】Node.js
的异步编程方式有效提高了应用性能,然而回调地狱却让人望而生畏,Promise
让我们告别回调函数;在实践过程中,却发现Promise
并不完美;技术进步是无止境的,后来有了Async/Await
,让我们能够写出阻塞式的异步处理代码,然而对于一些流程控制方面还是很难写出优雅的代码。async.js
的出现,能够写出简单清晰的异步流程控制代码。本文主要介绍项目中的常用方法。
项目官网:caolan.github.io/async/index…
简介
Async
是一个流程控制工具包,提供了直接而强大的异步功能。基于Javascript为NodeJs
设计,也可以直接在浏览器中使用。
在官方文档中,async.js
的功能分为三个部分:流程控制、集合处理、工具。包括常用的 map
, reduce
, filter
, forEach
等,异步流程控制模式包括:串行(series)
,并行(parallel)
,瀑布(waterfall)
等。
常用方法介绍
parallel
:多个任务并发执行
用于并行执行多个方法,所有传入的方法都是立即执行,方法之间没有数据传递。传递给最终callback
的数组中的数据按照tasks
中声明的顺序,而不是执行完成的顺序。
- 调用方式:parallel(tasks, [callback])
- 参数:
tasks
:需要执行多个方法。tasks
可以以数组形式传入,也可以以object
对象形式传入。每个方法都要一个回调方法callback(err, result)
,回调方法需要提供一个err
参数或是result
参数。当发生错误时(即:err
参数存在时),所有的方法停止执行,未执行完的方法将不会被传递至最终回调方法中。callback(err, results)
:可选的最终回调方法。出错时,tasks
中抛出的错误将在此方法中捕获,错误被传入err
参数。不出错时,tasks中回调结果将被写入results
参数中,以数据或对象形式提供。
- 示例:
// 此段代码实现在传入uid,获取用户信息、用户文章列表、文章评论信息 Async.parallel({ account: callback => { accountController.getByUid(keyword, callback); }, articles: callback => { articlesController.getByUid(keyword, callback); }, comments: callback => { commentsController.getByAid(keyword, callback); } }, (error, results) => { console.log(results) });
- 输出结果:
{ "account":{ "hash":"0x5eea3620415c6661912bb1c82aa7895f728e6258ea9d1b62f11acff7330f5cf1", "timestamp"1546076450, "name":"devpoint", }, "articles":[], "comments":null }
series:多个任务依次执行
用于依次执行多个方法,一个方法执行完毕后才会进入下一方法,方法之间没有数据传递。
- 调用方式:
series(tasks, [callback])
- 参数:
tasks
:需要执行多个方法。tasks可以以数组形式传入,也可以以object对象形式传入。每个方法都要一个回调方法callback(err, result),用于处理错误或进入下一方法。当发生错误时(即:err参数存在时),其后的方法会跳过,错误被传入最终回调方法中。
callback(err, results)
:可选的最终回调方法。出错时,tasks中抛出的错误将在此方法中捕获,错误被传入err参数。不出错时,tasks中回调结果将被写入results参数中,以数据或对象形式提供。- 示例
//以数组形式传入需要执行的多个方法 Async.series( [ callback => { // 执行一些操作后,callback进入下一方法 callback(null, "one"); }, callback => { // 执行一些操作后,callback进入可选的最终回调方法 callback(null, "two"); } ], // 可选的最终回调 (err, results) => { // 当tasks中的任一方法发生错误,即回调形式为callback('错误信息')时,错误将被传递给err参数,未发生错误err参数为空 // results中为数组中两个方法的结果数组:['one', 'two'] } ); //以object对象形式传入需要执行的多个方法 async.series( { one: callback => { // 执行一些操作后,callback进入下一方法 callback(null, 1); }, two: callback => { // 执行一些操作后,callback进入可选的最终回调方法 callback(null, 2); } }, (err, results) => { // 当tasks中的任一方法发生错误,即回调形式为callback('错误信息')时,错误将被传递给err参数,未发生错误err参数为空 // results中为数组中两个方法的结果对象:{one: 1, two: 2} } );
waterfall:多个函数依次执行,且前一个的输出为后一个的输入
与series
相似,按顺序依次执行多个函数。不同之处,每一个函数产生的值,都将传给下一个函数,如果中途出错,后面的函数将不会执行,错误信息以及之前产生的结果,都传给waterfall最终的callback。
这个函数的名字为waterfall(瀑布),可以想象瀑布从上到下,承上启下,有点类似于linux中的pipes。 注意该函数不支持object格式的tasks。
- 调用方式:
waterfall(tasks, [callback])
- 参数:
tasks
:需要执行多个方法。tasks只能以数组形式传入。每个方法都要一个回调方法callback(err, result1, result2, ...),用于处理错误或进入下一方法。当发生错误时(即:err参数存在时),其后的方法会跳过,错误被传入最终回调方法中。无错误时回调参数result1, result2……将做为下一方法的输入参数callback(err, results)
:可选的最终回调方法。出错时,tasks中抛出的错误将在此方法中捕获,错误被传入err参数。不出错时,tasks中回调结果results为最后一个方法的回调结果。
- 示例:
Async.waterfall( [ callback => { callback(null, "one", "two"); }, (arg1, arg2, callback) => { console.log("arg1=" + arg1 + ";arg2=" + arg2); callback(null, "three"); }, (arg1, callback) => { console.log("arg1=" + arg1); callback(null, "done"); } ], (err, result) => { //执行的任务中方法回调err参数时,将被传递至本方法的err参数 //参数result为最后一个方法的回调结果'done' console.log(result); } );
结果:
arg1=one;arg2=two arg1=three done
mapSeries:迭代执行,一个完了才执行下一个
迭代执行。将coll(是一个数组,不能是一个json对象)中的每一项依次拿给iterator去执行,执行结果传给最后的callback
- 调用方式:async.mapSeries(coll, iteratee, [callback])
- 参数:
coll
:迭代的集合iteratee
:迭代方法callback(err, results)
:可选的最终回调方法。
- 示例:
Async.mapSeries( [1, 2, 3, 4], (node, callback) => { callback(null, node + 1); }, (err, results) => { console.log(results); } );
结果:[ 2, 3, 4, 5 ]