nodejs Async详解之三:集合操作
Async提供了很多针对集合的函数,可以简化我们对集合进行异步操作时的步骤。如下:
forEach:对集合中每个元素进行异步操作
map:对集合中的每个元素通过异步操作得到另一个值,得到新的集合
filter:对集合中元素使用异步操作进行筛选,得到符合条件的集合
reject:与filter相似,只是判断条件时正好相反,得到剩下的元素的集合
reduce:使用一个初始值同集合中每一个元素进行异步操作,最后得到一个唯一的结果
detect:得到集合中满足条件的第一个数据
sortBy:对集合中的数据进行异步操作,再根据值从小到大排序
some/any:集合中是否有至少一个元素满足条件
every/all:集合中是否每个元素都满足条件
concat:对集合中的元素进行异步操作,将结果集合并成一个数组
下面一一解释:
1. forEach(arr, iterator(item, callback), callback(err))
如果想对同一个集合中的所有元素都执行同一个异步操作,可以利用forEach函数。注意该函数将重点放在“执行过程”上,忽略运行后产生的数据。如果需要结果,可使用map函数。
根据执行的方式不同,forEach提供了三个版本:
集合中所有元素并行执行
一个一个顺序执行
分批执行,同一批内并行,批与批之间按顺序
首先看并行执行的例子,它比较简单,只是打印出传入的元素内容:
var arr = [{name:'Jack', delay: 200},
{name:'Mike', delay: 100},
{name:'Freewind', delay: 300}];async.forEach(arr, function(item, callback) {
log(’1.1 enter: ‘ + item.name);
setTimeout(function(){
log(’1.1 handle: ‘ + item.name);
callback();
}, item.delay);
}, function(err) {
log(’1.1 err: ‘ + err);
});
它将打出如下结果:
42.244> 1.1 enter: Jack
42.245> 1.1 enter: Mike
42.245> 1.1 enter: Freewind
42.350> 1.1 handle: Mike
42.445> 1.1 handle: Jack
42.554> 1.1 handle: Freewind
42.554> 1.1 err: undefined
最前面的数据是当前的时间值(秒.毫秒),从中可以看到各异步操作是并行执行的。
如果想同步执行,需要使用forEachSeries函数,它与forEach的用法一模一样,只是执行时是一个一个来的。这里就不给例子了。
当集合中元素很多,既不想一次全部并行操作,又不想一个一个按顺序来,可以使用forEachLimit函数。它可以设定一批处理几个,每一批内并行执行,批与批之间顺序执行。
async.forEachLimit(arr, 2, function(item, callback) {
log(’1.5 enter: ‘ + item.name);
setTimeout(function(){
log(’1.5 handle: ‘ + item.name);
callback(null, item.name);
}, item.delay);
}, function(err) {
log(’1.5 err: ‘ + err);
});
打印结果如下:
42.247> 1.5 enter: Jack
42.248> 1.5 enter: Mike
42.351> 1.5 handle: Mike
42.352> 1.5 enter: Freewind
42.461> 1.5 handle: Jack
42.664> 1.5 handle: Freewind
42.664> 1.5 err: undefined
可以看到前两个是同时开始的,而第三个是等前两个都完成以后才开始的。
更多详细示例:https://github.com/freewind/async_demo/blob/master/forEach.js
2. map(arr, iterator(item, callback), callback(err, results))
map的重点是转换,即把集合中的元素通过异步操作转为另一个对象,最后可以得到转换后的对象数组。它也提供了并行与顺序执行两种方式。
这里给一个示例,给集合中的每个元素以异步方式增加!!!:
var arr = [{name:'Jack', delay:200}, {name:'Mike', delay: 100}, {name:'Freewind', delay:300}, {name:'Test', delay: 50}];
async.map(arr, function(item, callback) {
log(’1.1 enter: ‘ + item.name);
setTimeout(function() {
log(’1.1 handle: ‘ + item.name);
callback(null, item.name+’!!!’);
}, item.delay);
}, function(err,results) {
log(’1.1 err: ‘, err);
log(’1.1 results: ‘, results);
});
打印结果如下:
54.569> 1.1 enter: Jack
54.569> 1.1 enter: Mike
54.569> 1.1 enter: Freewind
54.569> 1.1 enter: Test
54.629> 1.1 handle: Test
54.679> 1.1 handle: Mike
54.789> 1.1 handle: Jack
54.879> 1.1 handle: Freewind
54.879> 1.1 err:
54.879> 1.1 results: [ 'Jack!!!', 'Mike!!!', 'Freewind!!!', 'Test!!!' ]
可以看到,对各元素的操作是并行的,结果会汇总在一起交给最后的回调。
如果想顺序执行,可使用mapSeries,它与map的用法一模一样。
更多详细示例:https://github.com/freewind/async_demo/blob/master/map.js
3. filter(arr, iterator(item, callback(test)), callback(results))
使用异步操作对集合中的元素进行筛选。需要注意的是,iterator的callback只有一个参数,只能接收true或false。
对于出错,该函数没有做出任何处理,直接由nodejs抛出。所以需要注意对Error的处理。
提供了并行与顺序执行两种方式。
并行示例,找到所有>=3的元素:
async.filter([1,2,3,4,5], function(item, callback) {
log(’1.1 enter: ‘ + item);
setTimeout(function() {
log(’1.1 test: ‘ + item);
callback(item>=3);
}, 200);
}, function(results) {
log(’1.1 results: ‘, results);
});
打印结果如下:
16.739> 1.1 enter: 1
16.749> 1.1 enter: 2
16.749> 1.1 enter: 3
16.749> 1.1 enter: 4
16.749> 1.1 enter: 5
16.749> 1.3 enter: 1
16.949> 1.1 test: 1
16.949> 1.1 test: 2
16.949> 1.1 test: 3
16.949> 1.1 test: 4
16.949> 1.1 test: 5
16.949> 1.1 results: [ 3, 4, 5 ]
可见找到了满足条件的所有元素。
如果需要顺序执行,可以使用filterSeries函数,它的用法与filter一样。
更多详细示例:https://github.com/freewind/async_demo/blob/master/filter_reject.js
4. reject(arr, iterator(item, callback(test)), callback(results))
reject与filter相似,只是行为正好相反。当条件为true时,它将丢弃相应的元素。它也提供了并行与顺序执行两种方式。
并行示例,去掉所有>=3的元素:
async.reject([1,2,3,4,5], function(item, callback) {
log(’1.4 enter: ‘ + item);
setTimeout(function() {
log(’1.4 test: ‘ + item);
callback(item>=3);
}, 200);
}, function(results) {
log(’1.4 results: ‘, results);
});
打印结果如下:
31.359> 1.4 enter: 1
31.359> 1.4 enter: 2
31.359> 1.4 enter: 3
31.359> 1.4 enter: 4
31.359> 1.4 enter: 5
31.559> 1.4 test: 1
31.559> 1.4 test: 2
31.559> 1.4 test: 3
31.559> 1.4 test: 4
31.559> 1.4 test: 5
31.569> 1.4 results: [ 1, 2 ]
如果想顺序执行,可使用rejectSeries,它与reject用法一样。
更多详细示例:https://github.com/freewind/async_demo/blob/master/filter_reject.js
5. reduce(arr, memo, iterator(memo,item,callback), callback(err,result))
Reduce可以让我们给定一个初始值,用它与集合中的每一个元素做运算,最后得到一个值。reduce从左向右来遍历元素,如果想从右向左,可使用reduceRight。
这里给个例子,计算出100与某个集合中所有数之和:
var arr = [1,3,5];
async.reduce(arr, 100, function(memo, item, callback) {
log(’1.1 enter: ‘ + memo +’, ‘ + item);
setTimeout(function() {
callback(null, memo+item);
}, 100);
},function(err, result) {
log(’1.1 err: ‘, err);
log(’1.1 result: ‘, result);
});
将打印出结果:
28.789> 1.1 enter: 100, 1
28.889> 1.1 enter: 101, 3
28.999> 1.1 enter: 104, 5
29.109> 1.1 err:
29.109> 1.1 result: 109
需要注意的是,async中的reduce,不是并行操作,而是对元素一个个顺序操作,所以当元素比较多时,性能会比较弱。如果想提高性能,可使用async.map函数,先并行得到集合中每个元素被处理之后的值,然后再使用Array.prototype.reduce函数处理,性能会快很多。
对于这个例子:
async.reduce(arr, 100, function(memo,item,callback) {
log(’1.4 enter: ‘+memo+’,'+item);
t.inc(item, function(err,n) {
log(’1.4 handle: ‘,n);
callback(null, memo+n);
});
}, function(err,result) {
log(’1.4 err: ‘, err);
log(’1.4 result: ‘, result);
});
它总耗时为0.62秒。如果换成map+array.reduce:
async.map(arr, function(item, callback) {
log(’1.5 enter: ‘, item);
t.inc(item, function(err,n){
log(’1.5 handle: ‘, n);
callback(null,n);
});
},function(err, results) {
log(’1.5 err: ‘, err);
log(’1.5 results: ‘, results);
var sum = results.reduce(function(memo, item) {
return memo + item;
}, 100);
log(’1.5 sum: ‘, sum);
});
耗时为0.21秒。
更多详细示例:https://github.com/freewind/async_demo/blob/master/reduce.js
6. detect(array, iterator(item,callback(test)), callback(result)
用于取得集合中满足条件的第一个元素。它分为并行与顺序执行两种方式,分别对应函数detect和detectSeries。
并行示例,找到一个奇数:
var arr = [{value:1,delay:500},
{value:2,delay:200},
{value:3,delay:300}];
async.detect(arr, function(item,callback){
log(’1.1 enter: ‘, item.value);
setTimeout(function() {log(’1.1 handle: ‘, item.value);
callback(n%2===1);
}, item.delay);
}, function(result) {
log(’1.1 result: ‘, result);
});
结果如下:
09.928> 1.1 enter: 1
09.928> 1.1 enter: 2
09.928> 1.1 enter: 3
10.138> 1.1 handle: 2
10.228> 1.1 handle: 3
10.228> 1.1 result: { value: 3, delay: 300 }
10.438> 1.1 handle: 1
10.438> 1.1 handle: 1
可见得到了最先执行完的那个奇数3.
更多详细示例:https://github.com/freewind/async_demo/blob/master/detect.js
7. sortBy(array, iterator(item,callback(err,result)), callback(err,results))
对集合内的元素进行排序,依据每个元素进行某异步操作后产生的值,从小到大排序。
示例:
var arr = [3,6,1];
async.sortBy(arr, function(item, callback) {
setTimeout(function() {
callback(null,item);
}, 200);
}, function(err,results) {
log(’1.1 err: ‘, err);
log(’1.1 results: ‘, results);
});
打印结果如下:
26.562> 1.1 err: null
26.562> 1.1 results: [ 1, 3, 6 ]
可以看到集合中的数据从小到大排好了序。
更多详细示例:https://github.com/freewind/async_demo/blob/master/sortBy.js
8. some/any(arr, iterator(item,callback(test)), callback(result))
当集合中是否有至少一个元素满足条件时,最终callback得到的值为true,否则为false。它有一个别名叫any。
判断集合中是否有元素小于等于3:
async.some([1,2,3,6], function(item,callback){
log(’1.1 enter: ‘,item);
setTimeout(function(){
log(’1.1 handle: ‘,item);
callback(item<=3);
},100);
}, function(result) {
log(’1.1 result: ‘, result);
});
打印结果如下:
36.165> 1.1 enter: 1
36.165> 1.1 enter: 2
36.165> 1.1 enter: 3
36.165> 1.1 enter: 6
36.275> 1.1 handle: 1
36.275> 1.1 result: true
36.275> 1.1 handle: 2
36.275> 1.1 handle: 3
36.275> 1.1 handle: 6
可见的确得到了结果true。
更多详细示例:https://github.com/freewind/async_demo/blob/master/some.js
9. every/all(arr, iterator(item,callback), callback(result))
如果集合里每一个元素都满足条件,则传给最终回调的result为true,否则为false
在下面的示例中,因为集合中每个元素都<=10,所以最终结果为true
async.every(arr, function(item,callback){
log(’1.1 enter: ‘,item);
setTimeout(function(){
log(’1.1 handle: ‘,item);
callback(item<=10);
},100);
}, function(result) {
log(’1.1 result: ‘, result);
});
打印如下:
32.113> 1.1 enter: 1
32.123> 1.1 enter: 2
32.123> 1.1 enter: 3
32.123> 1.1 enter: 6
32.233> 1.1 handle: 1
32.233> 1.1 handle: 2
32.233> 1.1 handle: 3
32.233> 1.1 handle: 6
32.233> 1.1 result: true
可见最终结果为true
更多详细示例:https://github.com/freewind/async_demo/blob/master/every.js
10. concat(arr, iterator(item,callback(err,result)), callback(err,result))
将合并多个异步操作的结果合并为一个数组。
在下面的示例中,将集合中的每一个元素都加倍:
async.concat(['aa','bb'], function(item,callback) {
setTimeout(function() {
callback(null, [item, item]);
}, 100);
}, function(err, values) {
log(’1.1 err: ‘, err);
log(’1.1 values: ‘, values);
});
打印如下:
13.539> 1.1 err:
13.639> 1.1 values: [ 'aa', 'aa', 'bb', 'bb' ]
打印出来的是经过合并后的数组。
更多详细示例:https://github.com/freewind/async_demo/blob/master/concat.js
nodejs Async详解之三:集合操作的更多相关文章
- nodejs Async详解之二:工具类
Async中提供了几个工具类,给我们提供一些小便利: memoize unmemoize log dir noConflict 1. memoize(fn, [hasher]) 有一些方法比较耗时,且 ...
- Fragment详解之三——管理Fragment(1)
相关文章: 1.<Fragment详解之一--概述>2.<Fragment详解之二--基本使用方法>3.<Fragment详解之三--管理Fragment(1)>4 ...
- [推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆)
原文:[推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆) [推荐]ORACLE PL/SQL编程详解之三: PL/SQL流程控制语句(不给规则,不成方圆) ...
- ASP.NET MVC Filters 4种默认过滤器的使用【附示例】 数据库常见死锁原因及处理 .NET源码中的链表 多线程下C#如何保证线程安全? .net实现支付宝在线支付 彻头彻尾理解单例模式与多线程 App.Config详解及读写操作 判断客户端是iOS还是Android,判断是不是在微信浏览器打开
ASP.NET MVC Filters 4种默认过滤器的使用[附示例] 过滤器(Filters)的出现使得我们可以在ASP.NET MVC程序里更好的控制浏览器请求过来的URL,不是每个请求都会响 ...
- App.Config详解及读写操作
App.Config详解及读写操作 App.Config详解 应用程序配置文件是标准的 XML 文件,XML 标记和属性是区分大小写的.它是可以按需要更改的,开发人员可以使用配置文件来更改设置,而 ...
- Nodejs this详解
[Nodejs this详解] Nodejs中, 文件层this,指向的是module.export. 函数层this,指向的是global对象. 参考:http://www.jb51.net/art ...
- AOP详解之三-创建AOP代理后记,创建AOP代理
AOP详解之三-创建AOP代理后记,创建AOP代理. 上篇文章已经获取到了AOP的信息,接下来就是拿着这些AOP的信息去创建代理了. 首先我们看下创建AOP代理的入口处. //这个方法将返回代理类 p ...
- Git详解之三 Git分支
相关文档 — 更多 Git 基础培训.ppt GIT 使用经验.ppt GIT 介绍.pptx GIT 分支管理是一门艺术.docx Eclipse上GIT插件EGIT使用手册.docx git/gi ...
- Async 详解
一:流程控制 为了适应异步编程,减少回调的嵌套,我尝试了很多库.最终觉得还是async最靠谱. 地址:https://github.com/caolan/async Async的内容分为三部分: 流程 ...
随机推荐
- 4 kafka集群部署及kafka生产者java客户端编程 + kafka消费者java客户端编程
本博文的主要内容有 kafka的单机模式部署 kafka的分布式模式部署 生产者java客户端编程 消费者java客户端编程 运行kafka ,需要依赖 zookeeper,你可以使用已有的 zo ...
- ThinkPHP Mongo驱动update方法支持upsert参数
Mongo数据库update操作有一个相对于Mysql的关键特性,它可以使用upsert模式,当更新的数据不存在时,直接插入,但是ThinkPHP的Mongo驱动居然不支持这一特性,没办法,自力更生了 ...
- 详解如何将MathType嵌入word中
将MathType嵌入word中的过程就是word插入对象的过程,插入对象是word软件中最常见的操作,MathType公式编辑器与所有的Office程序(OLE技术)都有很好的兼容性,本教程将详解如 ...
- 做BS开发,你应该知道的一些东西
界面和用户体验(Interface and User Experience) 知道各大浏览器执行Web标准的情况,保证你的站点在主要浏览器上都能正常运行.你至少要测试以下引擎:Gecko(用于Fire ...
- UI设计要学哪些软件
准备做UI设计的或是已经在做UI设计的童鞋,哪些软件是我们要学习的重点,作者把UI设计分成了好几个不同的职业方向,从事什么UI设计方向,就学什么软件,这样针对性就很强了,无论怎么说,Photoshop ...
- plsql developer中,清除登录历史
需求描述: 在使用plsql developer的时候,发现登录的时候,有太多的历史,想要把这些登录历史清除掉, 在此记录下. 操作过程: 1.登录plsql developer(或者在登录时取消也会 ...
- mongoDB的shell数组操作器
http://www.2cto.com/database/201304/205024.html mongoDB数组操作器 $push会向数组末尾加入一个元素,如果数组不存在,则会创建这个数组. 增 ...
- Ubuntu12.04 Skype4.2 提示Skype can't connect,安装Skype4.3
最近几天Skype突然不能登录啦,以为是自己密码记错啦,重置啦一下密码,发现仍然提示”Skype can't connect“,我的版本是Ubuntu12.04 Skype4.2 尝试啦很多办法仍然不 ...
- float类型如何转换为string类型
在一些很大的float类型的地方会用科学记数法表示,这个时候如果想完整记录下来,还是得转字符串,这里书写一个float类型转string类型的方法 <?php function float_to ...
- Python 爬虫知识点 - 淘宝商品检索结果抓包分析
一.抓包基础 在淘宝上搜索“Python机器学习”之后,试图抓取书名.作者.图片.价格.地址.出版社.书店等信息,查看源码发现html-body中没有这些信息,分析脚本发现,数据存储在了g_page_ ...