Async 异步转同步详细流程解释
安装
npm install async --save
https://github.com/caolan/async
Async的内容主要分为三部分
- 流程控制: 简化九种常见的流程的处理
- 集合处理:如何使用异步操作处理集中的数据
- 工具类:几个常用的工具类
本文主要介绍流程控制部分,后续内容持续更新,由于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的详细解释为
- 依次执行一个函数数组中的每个函数,每一个函数执行完成之后才能执行下一个函数。
- 如果任何一个函数向它的回调函数中传了一个error,则后面的函数都不会被执行,并且将会立刻将该error以及已经执行了的函数的结果,传给series中最后的那个callback。
- 将所有的函数执行完后(没有出错),则会把每个函数传给其回调函数的结果合并为一个数组,传给series最后的那个callback。
- 还可以以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中的不足
例如我要完成下面的事情
- 从某处取得数据
- 在硬盘上建立一个新的目录
- 将数据写入到目录下某文件
- 发送邮件
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,网址
Async 异步转同步详细流程解释的更多相关文章
- async异步改同步后怎么监听错误
当我们使用readFile()这种api,它第一个参数是报的错误,当使用async.await把它改写成同步,我们可以使用try { }catch{ }解决.
- ASP.NET sync over async(异步中同步,什么鬼?)
async/await 是我们在 ASP.NET 应用程序中,写异步代码最常用的两个关键字,使用它俩,我们不需要考虑太多背后的东西,比如异步的原理等等,如果你的 ASP.NET 应用程序是异步到底的, ...
- ajax中的async属性值之同步和异步及同步和异步区别
jquery中ajax方法有个属性async用于控制同步和异步,默认是true,即ajax请求默认是异步请求,有时项目中会用到AJAX同步.这个同步的意思是当JS代码加载到当前AJAX的时候会把页面里 ...
- 深入理解MVC C#+HtmlAgilityPack+Dapper走一波爬虫 StackExchange.Redis 二次封装 C# WPF 用MediaElement控件实现视频循环播放 net 异步与同步
深入理解MVC MVC无人不知,可很多程序员对MVC的概念的理解似乎有误,换言之他们一直在错用MVC,尽管即使如此软件也能被写出来,然而软件内部代码的组织方式却是不科学的,这会影响到软件的可维护性 ...
- Python并发编程06 /阻塞、异步调用/同步调用、异步回调函数、线程queue、事件event、协程
Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件event.协程 目录 Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件 ...
- 异步编程系列第01章 Async异步编程简介
p { display: block; margin: 3px 0 0 0; } --> 2016.10.11补充 三个月过去了,回头来看,我不得不承认这是一系列失败的翻译.过段时间,我将重新翻 ...
- 漫话JavaScript与异步·第三话——Generator:化异步为同步
一.Promise并非完美 我在上一话中介绍了Promise,这种模式增强了事件订阅机制,很好地解决了控制反转带来的信任问题.硬编码回调执行顺序造成的"回调金字塔"问题,无疑大大提 ...
- C# 异步转同步
当我们的程序运行时,调用了一段异步的逻辑A,这段异步的逻辑无法转化为同步(如动画.下载进度等) 而,我们又需要等待异步逻辑A处理完成,然后再执行其它逻辑B. 那就迫切需要将异步转同步了! //参数bo ...
- C#.NET使用Task,await,async,异步执行控件耗时事件(event),不阻塞UI线程和不跨线程执行UI更新,以及其他方式比较
使用Task,await,async,异步执行事件(event),不阻塞UI线程和不跨线程执行UI更新 使用Task,await,async 的异步模式 去执行事件(event) 解决不阻塞UI线程和 ...
随机推荐
- 设计一个 Java 程序,自定义异常类,从命令行(键盘)输入一个字符串,如果该字符串值为“XYZ”。。。
设计一个 Java 程序,自定义异常类,从命令行(键盘)输入一个字符串,如果该字符串值为“XYZ”,则抛出一个异常信息“This is a XYZ”,如果从命令行输入 ABC,则没有抛出异常.(只有 ...
- 【Android自动化】编写一个log模块,输出至控制台,供程序运行查看
# -*- coding:utf-8 -*- import logging def get_log(name): log = logging.getLogger(name) log.setLevel( ...
- 13.5.SolrCloud集群使用手册之数据导入
转载请出自出处:http://www.cnblogs.com/hd3013779515/ 1.使用curl命令方式 SolrCloud时会根据路由规则路由到各个shard. 删除所有数据 curl h ...
- 日常使用Shell积累
HDFS统计文件行数: hdfs dfs -cat hdfs://ns3/wordcount/* |wc -l
- docker构建Java环境
FROM java:7 COPY . /usr/src/javaapp WORKDIR /usr/src/javaapp RUN javac HelloWorld.java CMD ["ja ...
- PAT B1042 字符统计 (20 分)
请编写程序,找出一段给定文字中出现最频繁的那个英文字母. 输入格式: 输入在一行中给出一个长度不超过 1000 的字符串.字符串由 ASCII 码表中任意可见字符及空格组成,至少包含 1 个英文字母, ...
- Android ScrollView 嵌套ListView的替代方案
概要:本例仅提供替代思路. 原需求:实现下图这个布局 要求:头部菜单固定,实现Viewpager.中间的按钮菜单,底部的listview一起能够上下滚动. 做法: 把Viewpager.中间的按钮菜单 ...
- 利用WebHook实现PHP自动部署Git代码
平时项目代码都托管在Coding,然后每次提交了代码之后都要SSH到服务器上去git pull一次,很是繁琐,在看了OverTrue的<使用PHP脚本远程部署git项目>后就尝试在自己服务 ...
- awk、sed处理文件的简单例子
awk.sed对处理日志文件和写shell脚本时非常有益.这个东西,如果不经常操作,真心过一段时间就忘差不多..要掌握熟练,就要多练习,这没什么可说的. awk '条件{命令}' filename 假 ...
- STM32 CAN总线标识符过滤器难点解析
STM32 CAN总线标识符过滤器难点解析 原创 2016年05月31日 15:12:24 标签: stm32 / CAN 4910 CAN总线是目前应用非常多的一种总线,在汽车电子,航空航天中应用广 ...