安装

npm install async --save

地址

https://github.com/caolan/async

Async的内容主要分为三部分

  1. 流程控制: 简化九种常见的流程的处理
  2. 集合处理:如何使用异步操作处理集中的数据
  3. 工具类:几个常用的工具类

本文主要介绍流程控制部分,后续内容持续更新,由于node.js是异步编程模型,有许多在同步编程中很容易做到的事情,现在就会变的很麻烦,并且存在很多的callback。但是,Async的流程控制给我们coder带来了许多便利。


1.series(task, [callback])(多个函数依次执行,之间没有数据交换)

有多个异步函数需要依次调用,一个完成之后才能执行下一个。各函数之间没有数据交换,仅仅需要保证其顺序执行。这时可以使用series。

纯js代码

step1(function (err, v1) {
step2(function(err, v2){
step3(function(err,v3){
//code with the value [v1|v2|v3] or err
});
});
});

从上面的代码中可以看到,这些嵌套还是比较深的,如果操作更加复杂,那么会让代码的可读性降低。此外,在代码中忽略了对每一层err的处理,否则还要加上if(err) return callback(err);

那就更麻烦了。

对于这种情况,我们可以使用async来处理

var async = require('async');
async.series([
function(callback){
step1(function(err, v1){
//code with v1
callback(err, v1);
});
},
function(callback){step2(……)},
function(callback){step3(……)}
],function(err, values){
//code with the value [v1|v2|v3] or the err
});

上述async的详细解释为

  1. 依次执行一个函数数组中的每个函数,每一个函数执行完成之后才能执行下一个函数。
  2. 如果任何一个函数向它的回调函数中传了一个error,则后面的函数都不会被执行,并且将会立刻将该error以及已经执行了的函数的结果,传给series中最后的那个callback。
  3. 将所有的函数执行完后(没有出错),则会把每个函数传给其回调函数的结果合并为一个数组,传给series最后的那个callback。
  4. 还可以以json的形式提供tasks。每一个属性都会被当作函数来执行,并且结果也会以json形式传给series中最后的那个callback。这种方式可读性更高

注: 多个series调用之间是不分先后的,因为series本身也是异步调用。

2.parallel(tasks,[callback])(多个函数并行执行)

并行执行多个函数,每个函数都是立刻执行,不需要等待其他函数先执行。传给最终callback的数组中的数据按照tasks声明的顺序,而不是执行完成的顺序。

如果某个函数出错,则立刻将err和已经执行完的函数的结果值传给parallel最终的callback。其它为执行完的函数的值不会传到最终数据,但要占个位置。

同时支持json形式的tasks,其最终callback的结果也为json形式。

正常执行的代码如下:

async.parallel([
function(callback){t.fire('f400', callback, 400)},
function(callback){t.fire('f200', callback, 200)},
function(callback){t.fire('f300', callback, 300)}
],function(err, results){
log(err); //->undefined
log(results); //->['f400', 'f200', 'f300']
});

中途出错的代码如下:

async.parallel([
function(callback){t.fire('f400', callback, 400)},
function(callback){t.fire('f200', callback, 200)},
function(callback){t.err('e300', callback, 300)}
], function(err, results){
log(err); //->e300
log(results); //->[, 'f200', undefined]
});

3.waterfall(tasks, [callback])(多个函数依次执行,且前一个的输出为后一个的输入)

与series相似,按顺序依次执行多个函数。不同之处,每一个函数产生的值,都将传给下一个函数,如果中途出错,后面的函数将不会执行,错误信息以及之前产生的结果,都传给waterfall最终的callback。

这个函数的名字为waterfall(瀑布),可以想象瀑布从上到下,承上启下,有点类似于linux中的pipes。 注意该函数不支持json格式的tasks。

async.waterfall([
function(callback){log('start'), callback(null, 3)},
function(n, callback){log(n), t.inc(n, cb);/*inc为类似于i++的函数*/},
function(n, callback){log(n), t.fire(n*n, cb);}
], function(err, results){
log(err);
log(results);
}); /**
output start
3
4
err: null
results: 16
*/

4.auto(tasks, [callback])(多个函数有依赖关系, 有的并行执行,有的一次执行)

auto可以弥补parallel和series中的不足

例如我要完成下面的事情

  1. 从某处取得数据
  2. 在硬盘上建立一个新的目录
  3. 将数据写入到目录下某文件
  4. 发送邮件
async.auto({
getData: function(callback){
setTimeout(function(){
console.log('got data');
callback(null, 'mydata');
}, 300);
},
makeFolder: function(callback){
setTimeout(function() {
console.log('made folder');
callback(null, 'myfolder');
}, 200);
},
writeFile:['getData', 'makeFolder', function(callback){
setTimeout(function(){
console.log('write file');
callback(null, 'myfile');
}, 300);
}],
emailFiles: ['writeFile', function(callback, results){
log('send email');
callback(null, results.writeFile);
}]
},function(err, results){
log(err); //->null
log(results);
//made folder
//got data
//write file
//send email /*
results{
makeFolder: 'myfolder',
getData: 'mydata',
writeFile: 'myfile',
emailFiles: 'myfile'
}
*/
});

5.whilst(test, fn, callback)(该函数的功能比较简单,条件变量通常定义在外面,可供每个函数访问。在循环中,异步调用时产生的值实际上被丢弃了,因为最后的callback只能传入错误信息,另外,第二个函数fn需要接受一个函数的cb, 这个cb最终必需被执行,用于表示出错或正常结束)

var count = 0;
async.whilst(
//test
function(){return count < 3;},
function(cb){
log(count);
count++;
setTimeout(cb, 1000);
},
function(err){
//3s have passed
log(err);
}
);
/*
0
1
2
null
*/

6.until(test, fn, callback)(与whilst相似,但判断条件相反)

var count_until = 0;
async.until(
//test
function(){ return count_until > 3;},
function(cb){
log(count_until);
count_until++;
setTimeout(cb, 1000);
},
function(err){
//4s have passed
log(err);
}
);
/*
0
1
2
3
null
*/

7.queue(可设定worker数量的队列)

queue相当于一个加强版的parallel, 主要限制了worker数量,不再一次性全部执行。当worker数量不够用时,新加入的任务将会排队等候,直到有新的worker可用。

该函数有多个点可供回调,如worker用完时、无等候任务时、全部执行完时等。

//定义一个queue, 设worker数量为2
var q = async.queue(function(task, callback){
log('worker is processing task: ' + task.name);
task.run(callback);
}, 2);
//监听:如果某次push操作后, 任务数将达到或超过worker数量时, 将调用该函数
q.saturated = function(){
log('all workers to be used');
}
//监听:当最后一个任务交给worker时,将调用该函数
q.empty = function(){
log('no more tasks waiting');
}
//监听:当所有任务都执行完以后,将调用该函数
q.drain = function(){
log('all tasks have been processed');
} //独立加入两个任务
q.push({name : 't1', run: function(cb){
log('t1 is running, waiting tasks:' + q.length());
t.fire('t2', cb, 400); //400ms后执行
}}, function(err){
log('t1 executed');
}); log('pushed t1, waiting tasks:' + q.length()); q.push({name: 't2', run: function(cb){
log('t2 is running, waiting tasks:' + q.length());
t.fire('t2', cb, 200); //200ms后执行
}}, function(err){
log('t2 executed');
}); log('pushed t2, waiting tasks:' + q.length()); /**
pushed t1, waiting tasks:1
all workers to be used
pushed t2, waiting tasks:2
worker is processing task : t1
t1 is running, waiting tasks: 1
no more tasks waiting
worker is processing task : t2
t2 is running, waiting tasks: 0
t2 executed
t1 executed
all tasks have been processed
*/

8.iterator(tasks)(将几个函数包装为iterator)

将一组函数包装成为一个iterator, 可通过next()得到以下一个函数为起点的新的iterator。该函数通常由async在内部使用,但如果需要时,也可在我们的代码中使用它。

var iter = async.iterator([
function(){console.log('111');},
function(){console.log('222');},
function(){console.log('333');}
]); var it1 = iter();
it1();

其中还包括了next()方法。

9.nextTick(callback)(在nodejs与浏览器两边行为一致)

nextTick的作用和nodejs的nextTick一样,都是把某个函数调用放在队列的尾部,但在浏览器端,只能使用setTimeout(callback, 0),但这个方法有时候会让其它高优先级的任务插到前面去。

所以提供了这个nextTick,让同样的代码在服务器端和浏览器端表现一致。

var calls = [];
async.nextTick(function(){
calls.push('two');
});
calls.push('one');
async.nextTick(function(){
console.log(calls); //-> ['one', 'two']
})

上述内容为学习笔记,大部分内容摘抄自alsotang的github中的async_demo,网址

欢迎转载,转载请注明出处。

update by 2017/7/24 16:43

该部分已完结

by 一枝猪

Node.js中Async详解:流程控制的更多相关文章

  1. 《Node.js开发实战详解》学习笔记

    <Node.js开发实战详解>学习笔记 ——持续更新中 一.NodeJS设计模式 1 . 单例模式 顾名思义,单例就是保证一个类只有一个实例,实现的方法是,先判断实例是否存在,如果存在则直 ...

  2. (四)、 nodejs中Async详解之一:流程控制

    为了适应异步编程,减少回调的嵌套,我尝试了很多库.最终觉得还是async最靠谱. 地址:https://github.com/caolan/async Async的内容分为三部分: 流程控制:简化十种 ...

  3. nodejs中Async详解之一:流程控制

    为了适应异步编程,减少回调的嵌套,我尝试了很多库.最终觉得还是async最靠谱. 地址:https://github.com/caolan/async Async的内容分为三部分: 流程控制:简化十种 ...

  4. Node.js + Express中间件详解

    使用中间件 Express是一种路由和中间件Web框架,它具有自己的最小功能:Express应用程序本质上是一系列中间件函数调用. 中间件函数是可以访问请求对象 (req),响应对象(res)以及应用 ...

  5. node.js的npm详解

    一.什么是npm呢 npm(Node Package Manager,node包管理器)是node的包管理器,他允许开发人员在node.js应用程序中创建,共享并重用模块.模块就是可以在不同的项目中重 ...

  6. Node.js HTTP 使用详解

    对于初学者有没有发觉在查看Node.js官方API的时候非常简单,只有几个洋文描述两下子,没了,我第一次一口气看完所以API后,对于第一个示例都有些懵,特别是参数里的request和response, ...

  7. js中eval详解,用Js的eval解析JSON中的注意点

    先来说eval的用法,内容比较简单,熟悉的可以跳过eval函数接收一个参数s,如果s不是字符串,则直接返回s.否则执行s语句.如果s语句执行结果是一个值,则返回此值,否则返回undefined. 需要 ...

  8. js中arguments详解

    在js中一切都是对象,连函数也是对象,函数名其实是引用函数定义对象的变量. 什么是arguments? 这个函数体内的arguments非常特殊,实际上是所在函数的一个内置类数组对象,可以用数组的[i ...

  9. 阿里云ECS服务器部署Node.js项目全过程详解

    本文详细介绍如何部署NodeJS项目到阿里云ECS上,以及本人在部署过程中所遇到的问题.坑点和解决办法,可以说是全网最全最详细的教程了.同时讲解了如何申请阿里云免费SSL证书,以及一台ECS服务器配置 ...

随机推荐

  1. mysql 触发器(trigger)

    触发器(trigger):监视某种情况,并触发某种操作. 触发器创建语法四要素:1.监视地点(table) 2.监视事件(insert/update/delete) 3.触发时间(after/befo ...

  2. NYOJ 66 分数拆分

    分数拆分 时间限制:3000 ms  |  内存限制:65535 KB 难度:1   描述 现在输入一个正整数k,找到所有的正整数x>=y,使得1/k=1/x+1/y.   输入 第一行输入一个 ...

  3. spring-session实现分布式集群session的共享

    前言 HttpSession是通过Servlet容器创建和管理的,像Tomcat/Jetty都是保存在内存中的.但是我们把应用搭建成分布式的集群,然后利用LVS或Nginx做负载均衡,那么来自同一用户 ...

  4. HDU 6006 Engineer Assignment:状压dp

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6006 题意: 在Google中,有个n项目,m个专家.第i个项目涉及c[i]个领域,分别为a[i][0 ...

  5. Mysql查询优化器浅析

    --Mysql查询优化器浅析 -----------------------------2014/06/11 1 定义    Mysql查询优化器的工作是为查询语句选择合适的执行路径.查询优化器的代码 ...

  6. python之--------封装

    一.封装: 什么是封装呢?(封装不是单纯意义的隐藏,其实它还是可以查看的) 就是把一些不想让别人看的给隐藏起来了 封装数据:目的是保护隐私 功能封装:目的是隔离复杂度 如果用了私有的,在类的外部,无法 ...

  7. 页面引入css用link和import的区别

    假设有一个css文件a.css,文件里的内容如下: p { font-size: 18px; } 现在分别使用两种方式引入a.css: 1.使用html的link标签 <link rel=&qu ...

  8. 解析SS、SP、BP寄存器

    SS, SP, BP 三个寄存器 SS:存放栈的段地址: SP:堆栈寄存器SP(stack pointer)存放栈的偏移地址; BP: 基数指针寄存器BP(base pointer)是一个寄存器,它的 ...

  9. zyUpload---照片上传并显示效果

    demo 下载连接

  10. Azkaban3.x集群部署(multiple executor mode)

    介绍 Azkaban是由Linkedin公司推出的一个批量工作流任务调度器,用于在一个工作流内以一个特定的顺序运行一组工作和流程.Azkaban使用job配置文件建立任务之间的依赖关系,并提供一个易于 ...