安装

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. HTML+CSS+JS简介

    1.HTML与 CSS 1 1.1 HTML 1 1.2 HTML5 2 1.2.1 HTML5的特性 3 1.3  CSS 4 2.JavaScript 6 2.1特性 7 2.2编程 8 3.Sp ...

  2. 【head first python】2.共享你的代码 函数模块

    #coding:utf-8 #注释代码! #添加两个注释,一个描述模块,一个描述函数 '''这是nester.py模块,提供了一个名为print_lol()的函数, 这个函数的作用是打印列表,其中可能 ...

  3. SSE图像算法优化系列十:简单的一个肤色检测算法的SSE优化。

    在很多场合需要高效率的肤色检测代码,本人常用的一个C++版本的代码如下所示: void IM_GetRoughSkinRegion(unsigned char *Src, unsigned char ...

  4. echarts之词云随机颜色的配置

    echarts中的词云字体产生随机颜色,最主演的是要引入worldcloud.js,另外还要有jquery.js文件与echarts.js文件的引入,通过配置即可实现词云随机颜色的产生.下面为大家介绍 ...

  5. TCP/IP小记

    --TCP/IP小记 -----------------2014/06/11 TCP的要求是:local_ip:local_port <==>remote_ip:remote_port这个 ...

  6. 原创:使用脚本获取本机IP地址

    接来下又到了老葵花哥哥开课时间了 今天讲的有些简单 可以是涂鸦之做 也可以是无聊的发呆的杰作 我想取IP地址在大家生活中很常用 今天就给大家介绍我的六种使用脚本取IP地址的方法 很多人想问我 为什么是 ...

  7. virtual与static

    virtual与static不能同时作用于一个函数.根据面向对象的理论,virtual的成员函数是可以变子类覆盖的,是实现多态的重要手段.而static作用的成员函数表示该函数仅属于某个类. 下面是实 ...

  8. 一个项目经理对主流项目管理工具的对比:禅道VS华为软件开发云

    禅道与软件开发云对比分析报告 1. 产品介绍 禅道是易软天创出品的一款项目管理软件,集产品管理.项目管理.测试管理.文档管理.组织管理于一体,覆盖了项目管理和测试管理的核心流程. 华为软件开发云 (D ...

  9. 7.21.06 java内存模型

    资料来源:http://www.cnblogs.com/smile361/archive/2013/11/25/3441553.html 程序计数器: 当前线程所执行的字节码的行号指示器 本地方法栈: ...

  10. PHP 字符串替换

    这是2017上半年的第一篇学习笔记,也是最后一篇,捂脸- 在前几天的工作中,关于"银行卡"页面原型如下,其中,不同银行卡的卡号只保留了最后四位数字可以显示,其他数字均用*字符隐藏了 ...