node核心:异步流程控制
Node.js的异步是整个学习Node.js过程中重中之重。
1)异步流程控制学习重点
2)Api写法:Error-first Callback 和 EventEmitter
3)中流砥柱:Promise
4)终极解决方案:Async/Await
node.js必知必会
.Node.js SDK里callback写法必须会的。
Node.js学习重点: Async函数与Promise
1.中流砥柱:Promise
2.终极解决方案:Async/Await
1. Api 写法:Error-first Callback 和EventEmitter
1.1 Error-first Callback
定义错误有限的回调写法只需要注意2条规则即可:
- 回调函数的第一个参数返回的error对象,如果error发生了,它会作为第一个参数返回,如果没有,一般做法是返回null.
- 回调函数的第二个参数返回的是任何成功响应的结果数据。如果结果正常没有error发生,err会被设置为null,并在第二个参数就出返回成功结果数据。
下面让我们看一下调用函数示例,Node.js文档例最常采用下面这样的回调方式:
function(err,res){
//process the error and result
}
这里的 callback 指的是带有2个参数的函数:“err”和“res” 。语义上讲,非空的"err"相当于程序异常;而空的“err”相当于可以正常返回结果“res”,无任何异常。
1.2 EventEmitter
事件模块是 Node.js内置的对观察者模式“发布/订阅”(publish/subscribe)的实现,通过 EventEmitter属性,提供了一个构造函数。该构造函数的实例具有 on 方法,可以用来监听指定事件,并触发回调函数。任意对象都可以发布指定事件,被 EventEmitter 实例的 on方法监听到。
在node6之后,可以直接使用require('events')类
var EventEmitter = require('events')
var util = require('util')
var MyEmitter = function(){
}
util.inherits(MyEmitter,EventEmitter)
const myEmitter = new MyEmitter();
myEmitter.on('event',(a,b)=>{
console.log(a,b,this)
// Prints: a b {}
})
myEmitter.emit('event','a','b')
和jquery、vue 里的Event 是非常类似的。而且前端自己也有EventEmitter。
1.3 如何更好的查Node.js文档
API 是应用程序接口 Application Programming interface的简称。从Node.js异步原理,我们可以知道,核心在于Node.js SDK中API调用,然后交由EventLoop(Libuv)去执行,所以我们一定要熟悉Node.js的API操作。
Node.js的API都是异步的,同步的函数是奢求,要查API文档,在高并发场景下慎用。
笔者推荐使用 Desh和 Zeal查看离线文档,对api理解会深入很多,比IDE辅助要好,可以有效避免离开IDE就不会写代码的窘境。

1.4 中流砥柱:Promise
回调地狱
Node.js因为采用了错误优先的回调风格写法,导致sdk里导出都是回调函数,就会特别痛苦,经常会出现回调里嵌套回调的问题,大家都非常厌烦这种写法,称之为 Callback Hell,即回调地狱。一个经典的例子来自著名的Promise模块 q 文档里。
step1(function(value1){
step2(value1,function(value2){
step3(value2,function(value3){
step4(value3,function(){
// Do something with value4
});
});
});
});
这里只是做4步,嵌套了4层回调,如果更多步骤呢?很多新手浅尝辄止,到这儿就望而却步,粉转黑。这明显不够成熟,起码你要看看它的对应解决方案吧!
Promise最早也是在commonjs社区提出来的,当时提出了很多规范。比较接受的是promise/A规范。后来人们在这个基础上,提出了promise/A+规范,也就是实际上现在的业内推行的规范。ES6 也是采用的这种规范。
Promise意味着[许愿|承诺]一个还没有完成的操作,但在未来会完成的。与Promise最主要的交互方法是通过将函数传入它的then方法从而获取得Promise最终的值或Promise最终拒绝(reject)的原因。要点有三个:
- 递归,每个异步操作返回的都是promise对象
- 状态机: 三种状态转换,只在promise对象内部可以控制,外部不能改变状态
- 全局异常处理
定义
var promise = new Promise(function(resolve, reject) {
//do a thing,possibly async, then...
if (/*everything turned out fine*/) {
resolve("Stuff worked!")
}
else {
reject(Error("It broke"))
}
})
每个Promise定义都是一样的,在构造函数里传入一个匿名函数,参数是resolve和reject,分别代表成功和失败时候的处理。
调用
promise.then(function(text){
console.log(text)//Stuff worked!
return Promise.reject(new Error('我是故意的'))
}).catch(function(err){
console.log(err)
})
它的主要交互方式是通过then函数,如果Promise成功执行resolve了,那么它就会将resolve的值传给最近的then函数,作为它的then函数的参数。如果出错reject,那就交给catch来捕获异常就好了。
Promise 的最大优势是标准化,各类异步工具库都按照统一规范实现,即使是async函数也可以无缝集成。所以用 Promise 封装 API 通用性强,用起来简单,学习成本低。在async函数普及之前,绝大部分应用都是采用Promise来做异步流程控制的,所以掌握Promise是Node.js学习过程中必须要掌握的重中之重。
Bluebird是 Node.js 世界里性能最好的Promise/a+规范的实现模块,Api非常齐全,功能强大,是原生Promise外的不二选择。
好处如下:
- 避免Node.js内置Promise实现 问题,使用与所有版本兼容
- 避免Node.js 4曾经出现的内存泄露问题
- 内置更多扩展,timeout、 promisifyAll等,对Promise/A+规范提供了强有力的补充
在学习Node.js过程中,对于Promise了解多深入都不过分。
推荐学习资料
- Node.js最新技术栈之Promise篇 https://cnodejs.org/topic/560dbc826a1ed28204a1e7de
- 理解 Promise 的工作原理 https://cnodejs.org/topic/569c8226adf526da2aeb23fd
- Promise 迷你书 http://liubin.github.io/promises-book/
1.4 终极解决方案:Async/Await
Async/Await是异步操作的终
极解决方案,Koa 2在node 7.6发布之后,立马发布了正式版本,并且推荐使用async函数来编写Koa中间件。
这里给出一段Koa2应用里的一段代码:
exports.list = async(ctx, next)=>{
try {
let students = await Student.getAllAsync();
await ctx.render('students/index',{
students : students
})
} catch (err) {
return ctx.api_error(err)
}
}
它做了3件事儿
- 通过await Student.getAllAsync();来获取所有的students信息。
- 通过await ctx.render渲染页面
- 由于是同步代码,使用try/catch做的异常处理
是不是非常简单,现在Eggjs里也都是这样同步的代码。
(1)正常写法
const pkgConf = require('pkg-conf')
async function main(){
const config = await pkgConf('unicorn');
console.log(config.ranbow);
//true
}
main()
变态写法:
const pkgConf = require('pkg-conf');
(async ()=> {
const config = await pkgConf('unicorn')
console.log(config.ranbow)
//true
})()
(2)await + Promise
const Promise = require('bluedbird');
const fs = Promise.promisifyAll(require("fs"));
async function main(){
const contents = await fs.readFileAsync("myfile.js","utf8")
console.log(contents)
}
main()
(2)await + co + generator
const co = require('co')
const Promise = require('bluedbird')
const fs = Promise.promisifyAll(require("fs"))
async function mian(){
const contents = co(function* () {
var result = yield fs.readFileAsync("myfile.js","utf8")
return result;
})
console.log(contents)
}
main()
要点:
- co 的返回值是promise,所以await 可以直接接co.
- co 的参数是generator
- 在gennerator 里可以使用yield,而yield后面接的有5种可能,故而把这些可以yeild接的方式称为yieldable,即可以yield接的。
- Promises
- Thunks(functions)
- array(parallel execution)
- objects (parallel execution)
- Generators 和 GeneratorFunctions
由上面3种基本用法可以推出Async 函数要点如下:
- Async函数语义上非常好
- Async不需要执行器,它本身具备执行能力,不像Generator需要co模块
- Async函数的异常处理采用try/catch和Promise的错误处理,非常强大
- co作为Generator执行器是不错的,它更好的是当做Promise 包装器,通过Generator支持yieldable,最后返回Promise,是不是有点无耻?
小结:
这部分共讲了4个小点,都是极其直接的必须掌握的知识点。
- 异步流程控制学习重点
- 2)Api写法:Error-first Callback 和 EventEmitter
- 3)中流砥柱:Promise
- 4)终极解决方案:Async/Await
这里再提一下关于Node.js源码阅读问题,很多人api都还没完熟练就去阅读源码,这是非常不赞成的,不带着问题去读源码是比较容易迷失在大量代码中的。效果并不好。
先用明白,然后再去阅读Node.js源码,然后探寻libuv并发机制。很多人买了朴大的《深入浅出Node.js》一书,看了之后还是不太会用,不是书写的不好,而是步骤不对。
- Node in action和了不起的Node.js是入门的绝好书籍,非常简单,各个部分都讲了,但不深入,看了之后,基本就能用起来了
- 当你用了一段之后,你会对Node.js的运行机制好奇,为啥呢?这时候去读朴大的《深入浅出Node.js》一书就能够解惑。原因很简单,九浅一深一书是偏向底层实现原理的书,从操作系统,并发原理,node源码层层解读。如果是新手读,难免会比较郁闷。
- 实践类的可以看看雷宗民(老雷)和赵坤(nswbmw)写的书
我一般给大家的推荐是把Node in action读上5遍10遍,入门干活足够了。剩下的就是反复实践,多写代码和npm模块就好。
迷茫时学习Node.js最好的方法
Node.js 编写的包管理器 npm 已成为开源包管理了领域最好的生态,直接到2017年10月份,有模块超过47万,每周下载量超过32亿次,每个月有超过700万开发者使用npm。现在早已经超过60万个模块了。
这里就不一一举例了,给出一个迷茫时学习Node.js最好的方法吧!
"每天看10个npm模块"
对于学习Node.js迷茫的人来说,这是最好的方式,当你不知道如何做的时候,就要向前(钱)看,你要知道积累哪些技能对以后有好处。对于学习Node.js必经之路,一定是要掌握很多模块用法,并从中汲取技巧、思路、设计思想的。与其不知道学什么,为什么不每天积累几个技巧呢?
推荐一个repo即 https://github.com/parro-it/awesome-micro-npm-packages 小型库集合,一天看十个不是梦!
更多讨论 https://zhuanlan.zhihu.com/p/29625882
此为学习node的学习笔记,为了自己学习查阅,转自狼叔的教程,如果侵权请联系我删除
阅读原文
node核心:异步流程控制的更多相关文章
- js 异步流程控制之 avQ(avril.queue)
废话前言 写了多年的js,遇到过最蛋疼的事情莫过于callback hell, 相信大家也感同身受. 业界许多大大也为此提出了很多不错的解决方案,我所了解的主要有: 朴灵 event proxy, 简 ...
- 使用yield进行异步流程控制
现状 目前我们对异步回调的解决方案有这么几种:回调,deferred/promise和事件触发.回调的方式自不必说,需要硬编码调用,而且有可能会出现复杂的嵌套关系,造成"回调黑洞" ...
- Nodejs中使用异步流程控制Async
首先,我们都知道,Node基于事件驱动的异步I/O架构,所谓异步就是非阻塞,说白了就是一个事件执行了,我不必等待它执行完成后我才能执行下一个事件.所以在Node环境中的模块基本都是异步的,上一篇说到我 ...
- nodejs进阶(7)—async异步流程控制
Async介绍 Async是一个流程控制工具包,提供了直接而强大的异步功能.基于Javascript为Node.js设计,同时也可以直接在浏览器中使用. Async提供了大约20个函数,包括常用的 m ...
- 异步流程控制库GoWithTheFlow
异步流程控制库GoWithTheFlow 一个尾触发方式来控制异步流程的库, 有seq(顺序执行) par(同步执行) 两种方法 博客 http://notes.jetienne.com/2011/0 ...
- 【javascript】Promise/A+ 规范简单实现 异步流程控制思想
——基于es6:Promise/A+ 规范简单实现 异步流程控制思想 前言: nodejs强大的异步处理能力使得它在服务器端大放异彩,基于它的应用不断的增加,但是异步随之带来的嵌套.难以理解的代码让 ...
- node基础13:异步流程控制
1.流程控制 因为在node中大部分的api都是异步的,比如说读取文件,如果采用回调函数的形式,很容易造成地狱回调,代码非常不容易进行维护. 因此,为了解决这个问题,有大神写了async这个中间件.极 ...
- (一)Nodejs - 框架类库 - Nodejs异步流程控制Async
简介 Async是一个流程控制工具包,提供了直接而强大的异步功能 应用场景 业务流程逻辑复杂,适应异步编程,减少回调的嵌套 安装 npm insatll async 函数介绍 Collections ...
- async 异步流程控制规则
github 学习async网址 : https://github.com/caolan/async/ 1.Async 函数介绍 async 主要实现了三个部分的流程控制功能 1.集合:Collect ...
随机推荐
- linux--解决oracle sqlplus 中上下左右backspace不能用
1. 解决不能backspace 方法1: stty erase ^h 在oracle用户下:在用户环境配置文件.bash_profile中加入如下语句 stty erase ^h 方法2:在sec ...
- Dubbo(四) -- telnet命令
一.telnet的作用 当dubbo服务(即生产者)发布之后,我们可以通过telnet命令来来进行调试和管理,以及跟踪服务调用的次数. 注意:2.0.5以上版本服务提供端口支持telnet命令,协议一 ...
- 多进程模块:multiprocessing
多进程: (1) 前面我们学习的多线程,其实算不上真正的多线程,即使你开了很多个线程,在同一时间内只能有一个CPU核数来处理一个线程(2) 在 python 中,多进程算得上是真正的多线程,假设你的C ...
- oracle常用管理命令
启动数据库和监听 lsnrctl start sqlplus /nolog conn sys/as sysdba startup 查看当前的实例名 show parameter instance_n ...
- 旅游吧!我在这里 ——旅游相册POI搜索:找回你的足迹
版权声明:本文由林少彬原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/89 来源:腾云阁 https://www.qclou ...
- 关于sencha touch 用phonegap打包后,docked悬停的组件被手机软键盘遮挡的解决方法
这个问题应该算是phonegap的一个bug,在mainifest.xml 里android:windowSoftInputMode设置成了adjustpan,理论上不会出现遮挡悬停组件这种情况, 不 ...
- 使用Eclipse(以及intellij IDEA)配合JDWP对服务器上部署的代码进行调试
今天遇到了一个问题:同样的代码,在服务器上跑的时候会报空指针异常,但是在本地是没有问题的,看服务器上打印的日志只能看到异常信息,不能准确地定位到出问题的代码,于是就搜索了一下远程调试.结果还真的可以在 ...
- 【BZOJ2087】[Poi2010]Sheep 几何+DP
[BZOJ2087][Poi2010]Sheep Description Lyx的QQ牧场养了很多偶数个的羊,他是Vip,所以牧场是凸多边形(畸形).现在因为他开挂,受到了惩罚,系统要求他把牧场全部分 ...
- IDEA 配置
配置sublime主题: 击链接 http://www.riaway.com,选择并下载自己喜欢的主题 file -->import setting 到刚刚下载的主题jar包,之后导入,重起i ...
- pythonMD5加密
#MD5加密def md5_key(arg): hash = hashlib.md5() hash.update(arg) return hash.hexdigest()