async 异步流程控制
2016-05-29 16:24
711 查看
async是一个强大的异步流程控制库,其语义类似于
js对数组的操作。它提供了一系列非常强大而便捷的方法,有助于我们在
javascript单线程模型背景下写出优雅的逻辑控制代码。
牛刀小试
先从文件操作开始初步了解async函数库的作用:
使用
filter过滤出磁盘中存在的文件
const fs = require('fs'); const async = require('async'); async.filter(['f1', 'f2', 'f3'], function(it, callback) { fs.access(it, function(err) { callback(null, !err); }); }, function(err, results) { console.log(results); });
假设当前目录下存在以上三个文件,那么
results输出为:
['f1', 'f2', 'f3']
使用
map判断文件是否存在
async.map(['f1', 'f2', 'f3'], function(it, callback) { fs.exists(function(exists) { callback(null, exists); }); }, function(err, results) { console.log(results);//[true, true, true] });
以上两个例子分别使用了
access与
exists判断文件是否存在,关于两个
API的详细说明,请查看
nodejs官方文档
常用的多任务并行
function asyncTask(delay, arg) { return function(callback) { setTimeout(function() { console.log(arg + "done"); callback(null, arg); }, delay); }; } async.parallel([ asyncTask(10, "task1"), asyncTask(1, "task2"), asyncTask(100, "task3"), ], function(err, ret) { console.log(ret); });
asyncTask输出的顺序依次为:
[luncher@localhost async]$ node app.js task2done task1done task3done //ret [ 'task1', 'task2', 'task3' ]
可见虽然任务是并行的,但是最终的结果依然按照任务数组的顺序排列。
顺序执行任务
function asyncTask(delay, arg) { return function(callback) { setTimeout(function() { console.log(arg + "done"); callback(null, arg); }, delay); }; } async.series([ asyncTask(10, "task1"), asyncTask(1, "task2"), asyncTask(100, "task3"), ], function(err, ret) { console.log(ret); });
输出:
[luncher@localhost async]$ node app.js task1done task2done task3done [ 'task1', 'task2', 'task3' ]
可以看到任务按照传入的顺序依次执行。
集合类型多任务处理
each
each函数依次遍历数组执行回调函数:
function readFile(file, callback) { fs.readFile(file, function(err, ret) { console.log("readFile "+ file + " done"); callback(err); }); } async.each(['f1', 'f2', 'f3'], readFile, function(err) { console.log("all done"); });
需要注意的是,each不能保证迭代函数完成的顺序,这取决于用户的具体任务
forEachOf
each函数可以对数组进行遍历,如果想要遍历的是一个对象,那么需要用到
forEachOf.
function readFile(file, k, callback) { fs.readFile(file, function(err, ret) { console.log("readFile "+ k + " " + file + " done"); callback(err); }); } async.forEachOf({k1: "f1", k2: "f2", k3: "f3"}, readFile, function(err) { console.log("all done"); });
迭代函数第一个参数是
value,第二个参数是
key.
控制
each和
foEachOf的顺序
eachSeries与
forEachOf都是用来控制迭代函数的顺序执行:
function readFile(file, k, callback) { fs.readFile(file, function(err, ret) { console.log("readFile "+ k + " " + file + " done"); callback(err); }); } async.forEachOfSeries({k1: "f1", k2: "f2", k3: "f3"}, readFile, function(err) { console.log("all done"); });
这样程序的输出始终是:
[luncher@localhost async]$ node app.js readFile k1 f1 done readFile k2 f2 done readFile k3 f3 done all done
使用
apply包装异步任务
前面几个异步任务都需要人为的额外写一个函数,如
asyncTask,
async提供一个
apply语法糖用于解决此类问题:
// 使用 apply async.parallel([ async.apply(fs.writeFile, 'testfile1', 'test1'), async.apply(fs.writeFile, 'testfile2', 'test2'), ]); // 等同于 async.parallel([ function(callback){ fs.writeFile('testfile1', 'test1', callback); }, function(callback){ fs.writeFile('testfile2', 'test2', callback); } ]);
使用
Limit类函数控制并发数量
async为每个接口都提供了一个
Limit参数,用户限制并发数量,我们利用
filterLimit做一个简单的测试:
var count = 0; async.filterLimit([1, 10, 28, 90, 10], 2, function(it, callback) { count++; console.log(it + "开始"); console.log("并发数:", count); setTimeout(function() { count--; console.log(it + "结束"); callback(null); }, it); }, function(results) { console.log(results); });
输出:
[luncher@localhost async]$ node app.js 1开始 并发数: 1 10开始 并发数: 2 1结束 28开始 并发数: 2 10结束 90开始 并发数: 2 28结束 10开始 并发数: 2 10结束 90结束 null
可以看到,最大并发数也就是
2,虽然待执行任务大于
2.
async几乎提供了全类数组操作类型的接口,例如:
sortBy、
reduce、
some等,这里不再一一展开。
异步控制函数
前面介绍了两个异步流程控制函数:series和
parallel。下面介绍其他几个流程控制函数:
使用
whilst实现
while操作
whilst用于实现,类似于
while的效果,直到满足条件,否则持续执行回调函数。
var c = 0; async.whilst(function() { console.log("judge"); return c < 3; }, function(callback) { c++; console.log("try " + c); setTimeout(function() { callback(null, c); }, 1000); }, function(err, val) { console.log('err', err); console.log('value: ', val); });
输出:
[luncher@localhost async]$ node app.js judge try 1 judge try 2 judge try 3 judge err null value: 3
使用
waterFall解决异步任务依赖问题
async.waterfall([ function(callback) { callback(null, 'one', 'two'); }, function(arg1, arg2, callback) { // arg1 now equals 'one' and arg2 now equals 'two' callback(null, 'three'); }, function(arg1, callback) { // arg1 now equals 'three' callback(null, 'done'); } ], function (err, result) { // result now equals 'done' });
相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- Android学习笔记(二九):嵌入浏览器
- Android java 与 javascript互访(相互调用)的方法例子
- JavaScript演示排序算法
- javascript实现10进制转为N进制数
- 最后一次说说闭包
- Ajax
- 2019年开发人员应该学习的8个JavaScript框架
- HTML中的script标签研究
- 对一个分号引发的错误研究
- async.js 学习记录
- 异步流程控制:7 行代码学会 co 模块
- ES6 走马观花(ECMAScript2015 新特性)
- JavaScript拆分字符串时产生空字符的原因
- Canvas 在高清屏下绘制图片变模糊的解决方法
- Redux系列02:一个炒鸡简单的react+redux例子
- JavaScript 各种遍历方式详解