文档章节

nodejs中Async库介绍

piggybear
 piggybear
发布于 2015/02/16 10:32
字数 2660
阅读 72
收藏 0
点赞 0
评论 0

Async 地址:https://github.com/caolan/async

Async的内容分为三部分:

  • 流程控制:简化十种常见流程的处理
  • 集合处理:如何使用异步操作处理集合中的数据
  • 工具类:个常用的工具类

本文介绍其中最简单最常用的流程控制部分。
由于nodejs是异步编程模型,有一些在同步编程中很容易做到的事情,现在却变得很麻烦。Async的流程控制就是为了简化这些操作。

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

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

step1(function(err, v1) {
        step2(function(err, v2) {
                step3(function(err, v3) {
                        // do somethig with the err or values v1/v2/v3
                }
        }
});

从中可以看到这嵌套还是比较多深的,如果再多步,会更深。在代中忽略对了每一层err的处理,否则还都等上 if(err) return callback(err),那就更麻烦了。
对于这种情况,使用async来处理,就是这的:

var async = require(‘async’) async.series([step1, step2, step3],
function(err, values) {
        // do somethig with the err or values v1/v2/v3
});

可以看到代简洁了很多,而且自动处理每个回调中的错误。当然,这里只给出来最最简单的例子,在实际中,我们常会在每个step中执行一些操作,这时可写成:

var async = require(‘async’) async.series([function(cb) {
        step1(function(err, v1) {
                // do something with v1
                cb(err, v1);
        }),
        function(cb) {
                step2(...)
        },
        function(cb) {
                step3(...)
        }],
        function(err, values) {
                // do somethig with the err or values v1/v2/v3
        });

该函数的详细解释为:
依次执行一个函数数组中的每个函数,每一个函数执行完成之后才能执行下一个函数。
如果任何一个函数向它的回调函数中了一个error,则后面的函数都不会被执行,并且将会立刻会将该error以及已经执行了的函数的结果,给series中最后那个callback。
当所有的函数执行完后(没有出错),则会把每个函数给其回调函数的结果合并为一个数组,给series最后的那个callback。
还可以json的形式来提供tasks。每一个属性都会被当作函数来执行,并且结果也会以json形式给series最后的那个callback。这种方式可读性更高一些。
具体例子可参考:https://github.com/freewind/async_demo/blob/master/series.js
其代中还包含了:
如果中间某个函数出错,series函数如何处理
如果某个函数给回调的值为undefined, null, {}, []等,series如何处理
另外还需要注意的是:多个series调用之间是不分先后的,为series本身也是异步调用。

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

并行执行多个函数,每个函数都是立即执行,不需要等待其它函数先执行。给最终callback的数组中的数据按照tasks中声明的顺序,而不是执行完成的顺序。
如果某个函数出错,则立刻将err和已经执行完的函数的结果值给parallel最终的callback。其它未执行完的函数的值不会到最终数据,但要个位置。
同时支持json形式的tasks,其最终callback的结果也为json形式。
示例代:

async.parallel([function(cb) {
        t.fire('a400', cb, 400)
},
function(cb) {
        t.fire('a200', cb, 200)
},
function(cb) {
        t.fire('a300', cb, 300)
}],
function(err, results) {
        log(’1 err: ‘, err); // -> undefined
        log(’1 results: ‘, results); // ->[ 'a400', 'a200', 'a300' ]
});

中途出错的示例:

async.parallel([function(cb) {
        log('1: ', 'start');
        t.fire('a400', cb, 400)
},
// 该函数的值不会给最终callback,但要个位置
function(cb) {
        log('2: ', 'start');
        t.err('e200', cb, 200)
},
function(cb) {
        log('3: ', 'start');
        t.fire('a100', cb, 100)
}],
function(err, results) {
        log(’2 err: ‘, err); // -> e200
        log(’2 results: ‘, results); // -> [ , undefined, 'a100' ]
});

以json形式入tasks

async.parallel({
        a: function(cb) {
                t.fire(‘a400′, cb, 400)
        },
        b: function(cb) {
                t.fire(‘c300′, cb, 300)
        }
},
function(err, results) {
        log(’3 err: ‘, err); // -> undefined
        log(’3 results: ‘, results); // -> { b: ‘c300′, a: ‘a400′ }
});

更详细示例参见:https://github.com/freewind/async_demo/blob/master/parallel.js

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

与seires相似,按顺序依次执行多个函数。不同之处,每一个函数产生的值,都将给下一个函数。如果中途出错,后面的函数将不会被执行。错误信息以及之前产生的结果,将给waterfall最终的callback。
这个函数名为waterfall(瀑布),可以想像瀑布从上到下,中途冲过一层层突起的石头。注意,该函数不支持json式的tasks。

async.waterfall([function(cb) {
        log('1: ', 'start');
        cb(null, 3);
},
function(n, cb) {
        log('2: ', n);
        t.inc(n, cb);
},
function(n, cb) {
        log('3: ', n);
        t.fire(n * n, cb);
}],
function(err, result) {
        log(’1 err: ‘, err); // -> null
        log(’1 result: ‘, result); // -> 16
});

更详细示例参见:https://github.com/freewind/async_demo/blob/master/waterfall.js

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

用来处理有依赖关系的多个任务的执行。比如某些任务之间彼此独立,可以并行执行;但某些任务依赖于其它某些任务,只能等那些任务完成后才能执行。
虽然我们可以使用async.parallel和async.series结合起来实现该功能,但如果任务之间关系复杂,则代会相当复杂,以后如果想添一个新任务,也会很麻烦。这时使用async.auto,则会事半功倍。
如果有任务中途出错,则会把该错误给最终callback,所有任务(包括已经执行完的)产生的数据将被忽略。
这里假设我要写一个程序,它要完成以下件事:
从某处取得数据
在硬盘上建立一个新的目录
将数据写入到目录下某文件
发送邮件,将文件以附件形式发送给其它人。
分析该任务,可以知道1与2可以并行执行,3需要等1和2完成,4要等3完成。

async.auto({
        getData: function(callback) {
                setTimeout(function() {
                        console.log(’1 : got data’);
                        callback();
                },
                300);
        },
        makeFolder: function(callback) {
                setTimeout(function() {
                        console.log(’1 : made folder’);
                        callback();
                },
                200);
        },
        writeFile: ['getData', 'makeFolder',
        function(callback) {
                setTimeout(function() {
                        console.log('1: wrote file');
                        callback(null, 'myfile');
                },
                300);
        }],
        emailFiles: ['writeFile',
        function(callback, results) {
                log('1: emailed file: ', results.writeFile); // -> myfile
                callback(null, results.writeFile);
        }]
},
function(err, results) {
        log(’1 : err: ‘, err); // -> null
        log(’1 : results: ‘, results); // -> { makeFolder: undefined,
        // getData: undefined,
        // writeFile: ‘myfile’,
        // emailFiles: ‘myfile’ }
});

更多详细示例参见:https://github.com/freewind/async_demo/blob/master/auto.js

whilst(test, fn, callback)(用可于异步调用的while)

相当于while,但其中的异步调用将在完成后才会进行下一次循环。举例如下:

var count1 = 0;
async.whilst(function() {
        return count1 < 3
},
function(cb) {
        log(’1 count: ‘, count1);
        count1++;
        setTimeout(cb, 1000);
},
function(err) {
        // 3s have passed
        log(’1 err: ‘, err); // -> undefined
});

它相当于:

try {
    whilst(test) {
        fn();
    }
    callback();
} catch(err) {
    callback(err);
}

该函数的功能比较简单,条件变量通常定义在外面,可供每个函数访问。在循环中,异步调用时产生的值实际上被丢弃了,为最后那个callback只能入错误信息。
另外,第二个函数fn需要能接受一个函数cb,这个cb最终必须被执行,用于表示出错或正常结束。
更详细示例参见:https://github.com/freewind/async_demo/blob/master/whilst_until.js

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

var count4 = 0;
 async.until(function() {
     return count4 > 3
 },
 function(cb) {
     log(’4 count: ‘, count4);
     count4++;
     setTimeout(cb, 200);
 },
 function(err) {
     // 4s have passed
     log(’4 err: ‘, err); // -> undefined
 });

当第一个函数条件为false时,继续执行第二个函数,否则跳出。

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);

worker数量将用完时,会调用saturated函数:

q.saturated = function() {
       log(‘all workers to be used’);
   }

当最后一个任务交给worker执行时,会调用empty函数

q.empty = function() {
       log(‘no more tasks wating’);
   }

当所有任务都执行完时,会调用drain函数

q.drain = function() {
       console.log(‘all tasks have been processed’);
   }

放入多个任务,可一次放一个,或一次放多个

q.push({
        name: ’t1′,
        run: function(cb) {
                log(‘t1 is running, waiting tasks: ‘, q.length());
                t.fire(‘t1′, cb, 400); // 400ms后执行
        }
},
function(err) {
        log(‘t1 executed’);
});

q.push([{
        name: 't3',
        run: function(cb) {
                log('t3 is running, waiting tasks: ', q.length());
                t.fire('t3', cb, 300); // 300ms后执行
        }
},
{
        name: 't4',
        run: function(cb) {
                log('t4 is running, waiting tasks: ', q.length());
                t.fire('t4', cb, 500); // 500ms后执行
        }
}],
function(err) {
        log(‘t3 / 4 executed’);
});

更多详细示例参见:https://github.com/freewind/async_demo/blob/master/queue.js

iterator(tasks) (将个函数包装为iterator)

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

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

直接调用(),会执行当前函数,并返回一个由下个函数为起点的新的iterator。调用next(),不会执行当前函数,直接返回由下个函数为起点的新iterator。
对于同一个iterator,多次调用next(),不会影响自己。如果只剩下一个元,调用next()会返回null。
更详细示例参见:https://github.com/freewind/async_demo/blob/master/iterator.js

apply(function, arguments..) (给函数预绑定参数)

apply是一个非常好用的函数,可以让我们给一个函数预绑定多个参数并生成一个可直接调用的新函数,简化代。
对于函数:

function(callback) { t.inc(3, callback); }

可以用apply改写为:

async.apply(t.inc, 3);

还可以给某些函数预设值,得到一个新函数:

var log = async.apply(console.log, ">");
   log(‘hello’);
   // > hello

更详细代参见:https://github.com/freewind/async_demo/blob/master/apply.js

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' ]
});

更详细代参见:https://github.com/freewind/async_demo/blob/master/nextTick.js

文章出处:  开源中国 
文章地址:  http://my.oschina.net/huangsz/blog/176203 
本文地址:  http://www.webrube.com/node.js-web_rube/1468 
本文由  噜吧 整理,转载请保留以上信息; 如有侵犯您的版权, 请联系微信: 3715397 。

© 著作权归作者所有

共有 人打赏支持
piggybear
粉丝 3
博文 237
码字总数 37552
作品 0
西安
技术主管
【深入浅出Node.js系列十四】Nodejs异步流程控制Async

深入浅出Node.js系列 【深入浅出Node.js系列一】什么是Node.js 【深入浅出Node.js系列二】Node.js&NPM的安装与配置 【深入浅出Node.js系列三】深入Node.js的模块机制 【深入浅出Node.js系列四...

陶邦仁 ⋅ 2016/01/19 ⋅ 0

Chrome V8 与 Node.js

从某种意义上来说,Node.js 并不是一个从零开始编写的 JavaScript 运行时,它其实也是站在“巨人的肩膀”上进行了一系列的拼凑和封装得到的结果。它的高效离不开一些很牛的第三方程序和类库。...

博文视点 ⋅ 06/14 ⋅ 0

【深入浅出Node.js系列十三】用Nodejs连接MySQL

深入浅出Node.js系列 【深入浅出Node.js系列一】什么是Node.js 【深入浅出Node.js系列二】Node.js&NPM的安装与配置 【深入浅出Node.js系列三】深入Node.js的模块机制 【深入浅出Node.js系列四...

陶邦仁 ⋅ 2016/01/19 ⋅ 0

Node.js与Golang使用感受与小结【三】--JS异步流程控制(序列模式、并发模式、有限...

Node.js与Golang使用感受与小结 目录 一、互联网的基石TCP/IP协议 二、HTTP服务器编写与编程语言无关 三、构建HTTP服务器需要掌握的知识点 四、HTTP协议基础 五、Node.js简介 六、是前端选择...

念念之间 ⋅ 2013/06/13 ⋅ 1

Nodejs学习路线图

Node.js的介绍 Node.js的是建立在Chrome的JavaScript的运行时,可方便地构建快速,可扩展的网络应用程序的平台。Node.js使用事件驱动,非阻塞I/O模型,轻量、高效,可以完美地处理时时数据,...

数通畅联 ⋅ 2016/01/26 ⋅ 0

Node.JS 学习路线图

 从零开始nodejs系列文章, 将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的 Javascript引擎。chrome浏览器就基于V8,同时打开...

永和 ⋅ 2016/06/12 ⋅ 1

Node.JS 学习路线图

原文出处:张丹的博客(@ConanZ) 从零开始nodejs系列文章, 将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的 Javascript引擎。...

张丹的博客(@Conan_Z) ⋅ 2014/06/24 ⋅ 0

Node.js学习路线图

Node.js学习路线图 从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome浏览器就基...

萨斯辈的呼唤 ⋅ 2015/07/19 ⋅ 0

node异步转同步,KO 恶魔金字塔

前言 Nodejs框架类库很多,功能相近的框架,本来只打算学一种写一种。之前写过流程控制框架windjs文章,本来是想着要支持一下“国人框架”。无奈啊,作者竟然放弃了维护,国人真的不靠谱啊!...

纯洁徐 ⋅ 2014/12/17 ⋅ 0

Node.js 7.0安装体验和示例代码解读

Node.js 7.0安装体验和示例代码解读 菜神 @fundon 大晚上不睡觉,放毒:https://github.com/pauliusuza/node-v7-async-await-demo?utmcontent=buffer9bce9&utmmedium=social&utmsource=twit......

i5ting ⋅ 2016/10/19 ⋅ 2

没有更多内容

加载失败,请刷新页面

加载更多

下一页

IDEA创建SpringMVC+Mybatis+Maven项目

视频如下(加载有点慢请见谅,服务器不太好): 视频

影狼 ⋅ 21分钟前 ⋅ 0

前阿里P8架构师:精准定制Java架构师学习计划!

可以说,Java是现阶段中国互联网公司中,覆盖度最广的研发语言,掌握了Java技术体系,不管在成熟的大公司,快速发展的公司,还是创业阶段的公司,都能有立足之地。 有不少朋友问,除了掌握J...

java高级架构牛人 ⋅ 24分钟前 ⋅ 0

zookeper学习

https://blog.csdn.net/u012152619/article/category/6470028

~少司命~ ⋅ 25分钟前 ⋅ 0

Spring MVC ,JSON,JQuery,不懂JQuery,跳过了

/spring-mvc-study/src/main/webapp/course_json.jsp <%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD ......

颖伙虫 ⋅ 25分钟前 ⋅ 0

2018上海云栖大会workshop-日志数据采集与分析对接

摘要: 日志数据采集与分析对接 课程描述 通过日志服务采集用户、数据库、业务等访问数据。演示对于业务日志分析与处理,程序日志查询与监控,打通日志与数据仓库对接案例。 日志种类 网站访...

阿里云云栖社区 ⋅ 26分钟前 ⋅ 0

mahout demo

package com.datamine.CollaborativeFiltering.mysql; import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood; import org.apache.mahout.cf.taste.impl.recommend......

xiaomin0322 ⋅ 28分钟前 ⋅ 0

red hat openstack 12配置要求

安装 openstack 之前,一般要规划整个系统中,到底要多少台机器来参与openstack, 根据rhosp12的官方文档: 最低要求是3台物理机,1台作为director,一台作为 controller ,一台作为computer....

tututu_jiang ⋅ 29分钟前 ⋅ 0

Rocket-Chip在GitHub上的各个源码

在github上通过搜索Rocket-chip可以得到36个结果:其中 https://github.com/freechipsproject/rocket-chip https://github.com/ucb-bar/riscv-boom https://github.com/ucb-bar/fpga-zynq (......

whoisliang ⋅ 34分钟前 ⋅ 0

【HAVENT原创】CentOS 6.5 下 Nginx 的安装与配置

nginx是轻量级的Web服务器、反向代理服务器及邮件服务器,具有占用内存少,并发能力强的优点,已被广泛应用。本文介绍目前最新版本 1.12.2 的安装。 各版本nginx下载地址:http://nginx.org/...

HAVENT ⋅ 40分钟前 ⋅ 0

查看linux系统重启之前的log -- last_kmsg

当 Linux Kernel 出现 BUG 的时候,后走入 panic flow,这个时候由于 Kernel 出现了严重的问题,adbd 也无法响应 adb 连接请求,这个时候想透过读取 Kernel Log Buffer 来看 Kernel Log 是不...

zyzzu ⋅ 41分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部