文档章节

读书笔记:深入理解ES6(十一)

张森ZS
 张森ZS
发布于 10/22 12:07
字数 2170
阅读 38
收藏 0

第十一章 Promise与异步编程

  Promise可以实现其他语言中类似Future和Deferred一样的功能,是另一种异步编程的选择,它既可以像事件和回调函数一样指定稍后执行的代码,也可以明确指示代码是否成功执行。

 

第1节 异步编程的背景知识

  1. 机制

    JavaScript引擎是基于单线程(Single-threaded)事件循环的概念构建,即同一时刻只允许一个代码块在执行。这些代码块被放在一个任务队列(job queue)中,每当一段代码准备执行时,都会被添加到任务队列。每当JavaScript引擎中的一段代码结束执行,事件循环(event loop)会执行队列中下一个任务。事件循环是JavaScript引擎的一段代码,负责监控代码执行并管理任务队列。

  2. 事件模型

    例如点击按钮或者按下键盘按键会触发的onclick事件,是JavaScript中最基础的异步编程形式。尽管事件模型适用于响应用户交互和完成类似的低频功能,但对更复杂的需求来说却不是很灵活。

  3. 回调模式

    回调模式和事件模型类似,异步代码都会在未来的某个时间点执行,二者的区别是回调模式中被调用的函数是作为参数传入的。例如:

复制代码
1 readFile("example.txt", function(err, contents) {
2     if (err) {
3         throw err;
4     }
5     console.log(contents);
6 });
7 console.log("Hi");
复制代码

    相比之下,回调模式比事件模型更灵活,但想要实现更复杂的功能时,回调函数的局限性同样会显现出来。

 

第2节 Promise的基础知识

  Promise相当于异步操作结果的占位符,它不去订阅事件,也不会传递一个回调函数给目标参数,而是让函数返回一个Promise。例如:

1 //readFile承诺将在未来某一个时刻完成
2 let promise = readFile("example.txt");

  1. Promise的声明周期

    a) Promise先是处于进行中(pending)的状态,此时操作尚未完成;等异步操作执行结束后,Promise变为已处理(settled)状态。分为如下两种状态:

    

    b)Promise的状态改变时,调用then()方法来采取特定的行动。

      then()方法接受2个参数:第一个参数是变为fulfilled时要调用的函数,第2个是状态变为rejected时需要调用的函数。

      Promise还有一个catch()方法,相当于只给其传入拒绝处理程序的then()方法。

 

  2. 创建未完成的Promise

    用Promise构造函数可以创建新的Promise,构造函数只接受一个参数:包含初始化Promise代码的执行器(executor)函数。执行器接受2个参数,分别是执行成功完成时调用的resolve()函数,执行失败时,调用reject()函数。

    执行器函数会立即执行,然后才执行后续流程中的代码(即resolve() / reject()会放到任务队列中再执行)。

 

  3. 创建已处理的Promise

    使用Promise.resolve() / Promise.reject()来实现根据特定的值来创建已解决的Promise。例如:

复制代码
1 let promise = Promise.resolve(42);
2 promise.then(function(value) {
3     console.log(value); //42
4 });
5 
6 let promise = Promise.reject(42);
7 promise.catch(function(value){
8     console.log(value); // 42
9 });
复制代码

 

  4. 执行器错误

    每个执行器中都隐含一个try-catch块,所以错误会被捕获并传入拒绝处理程序。

 

第3节 全局的Promise拒绝处理

  如果在没有拒绝处理程序的情况下,拒绝一个Promise,那么不会提示信息。Promise的特性决定了很难检测一个Promise是否被处理过。Node.js和浏览器分别做了一些改变来解决开发者这个痛点。

  1. Node.js环境的拒绝处理

    在Node.js中,处理Promise拒绝时会触发Promise对象上的两个事件:

    ·unhandledRejection  在一个事件循环中,当Promise被拒绝,并且没有提供拒绝处理程序时,触发该事件。

    ·rejectionHandled  在一个事件循环后,当Promise被拒绝,若拒绝处理程序被调用,触发该事件。

    具体代码参考P.249

 

  2. 浏览器环境的拒绝处理

    a) 浏览器也是通过触发两个事件来识别未处理的拒绝的,虽然这些事件是在window对象上触发的,但实际上与Node.js中完全等效。

      ·unhandledRejection  在一个事件循环中,当Promise被拒绝,并且没有提供拒绝处理程序时,触发该事件。

      ·rejectionHandled  在一个事件循环后,当Promise被拒绝,若拒绝处理程序被调用,触发该事件。

    b) 在Node.js实现中,事件处理程序接受多个参数;而在浏览器中,事件处理程序接受一个有以下属性的事件对象作为参数:

      ·type  事件名称("unhandledReject"或“rejectionHandled”);

      ·promise  被拒绝的Promise对象

      ·reason  来自Promise的拒绝值

    c) 浏览器实现的另一处不同是,在两个事件中都可以使用拒绝值(reason)。代码参考:P.251

 

第4节 串联Promise

  记住一个原则:只有当第一个Promise完成或被拒绝后,第二个才会被解决。

  1. 捕获错误

    在完成处理程序和拒绝处理程序中可能也会发生错误,而Promise链可以用来捕获这些错误。

    链式Promise调用可以感知到链中其他Promise的错误。

 

  2. Promise链的返回值

     Promise链的另一个重要特性是可以给下游Promise传递数据。在完成处理程序和拒绝处理程序中都可以这么做。

       代码参考P.255

 

  3. 在Promise链中返回Promise

    先定义的Promise的执行器先执行,后定义的后执行。

 

第5节 响应多个Promise

  之前讲的都是单Promise响应。如果想通过监听多个Promise来决定下一步的操作,可以使用ES6提供的Promise.all()和Promise.race()两个方法来监听多个Promise。

  1. Promise.all()方法

    该方法只接受一个参数并返回一个Promise,该参数是一个含有多个受监视Promise的可迭代对象,只有当可迭代对象中所有Promise都被解决后,返回的Promise才会被解决,只有当可迭代对象中所有Promise都被完成后返回的Promise才会被完成。

    其中,有两种情况:

    

 

     我们看看这两种情况,分别怎么处理:

       1. 当迭代对象中所有的Promise都被解决并返回后,最后的Promise里面存的值按照传入参数数组中的Promise的顺序储存。例如:

复制代码
 1 let p1 = new Promise(function(reolve, reject) {
 2     resolve(42);
 3 });
 4 
 5 let p2 = new Promise(function(resolve, reject) {
 6     resolve(43);
 7 });
 8 
 9 let p3 = new Promise(function(resolve, reject) {
10     resolve(44);
11 });
12 
13 let p4 = Promise.all([p1, p2, p3]);
14 
15 p4.then(function(value) {
16     console.log( Array.isArray(value) ); // true
17     console.log( value[0] ); // 42
18     console.log( value[1] ); // 43
19     console.log( value[2] ); // 44
20 });
复制代码

      2.当迭代对象中有被拒绝的Promise时,只要有一个被拒绝,那么返回的Promise没等所有Promise都完成就立即被拒绝,例如:

复制代码
 1 let p1 = new Promise(function(reolve, reject) {
 2     resolve(42);
 3 });
 4 
 5 let p2 = new Promise(function(resolve, reject) {
 6     reject(43);
 7 });
 8 
 9 let p3 = new Promise(function(resolve, reject) {
10     resolve(44);
11 });
12 
13 let p4 = Promise.all([p1, p2, p3]);
14 
15 p4.then(function(value) {
16     console.log( Array.isArray(value) ); // true
17     console.log( value ); // 43
18 });
复制代码

 

  2. Promise.race()方法

    Promise.race()与Promise.all()稍有不同。在可迭代对象中,只要有一个Promise被解决,返回的Promise就解决,无须等到所有Promise都被完成。

    如果先解决的是已完成Promise,则返回已完成Promise;如果先解决的是已拒绝的Promise,则返回已拒绝Promise。看个例子:

复制代码
 1 let p1 = new Promise(function(resolve, reject) {
 2     setTimeout(function() {resolve(42);}, 0);
 3 });
 4 
 5 let p2 = Promise.reject(43);
 6 
 7 let p3 = new Promise(function(resolve,reject) {
 8     resolve(44)
 9 });
10 
11 let p4 = Promise.race([p1, p2, p3]);
12 
13 p4.catch(function(value) {
14     console.log(value); // 43
15 });
复制代码

 

第6节 自Promise继承

  Promise也是基类,因为也可以派生其它类。

  例子参考代码P.262

 

第7节 基于Promise的异步任务执行

  只要每个异步操作都返回Promise,以Promise作为通用接口用于所有异步代码可以简化任务执行器。

  例子参考代码P.265

 

(本节完)

© 著作权归作者所有

张森ZS
粉丝 0
博文 24
码字总数 28351
作品 0
海淀
私信 提问
我的RabbitMQ的学习成果

背景 在研发分布式事务的最终一致性事务模式时,使用了RabbitMQ。 在这之前也接触过RabbitMQ,但没有特别深入的去了解它的特性与原理。这次决定系统的学习一次,所以业余时间阅读大神们的书籍...

XuePeng77
04/15
285
0
《Linux内核设计与实现》读书笔记 - 目录 (完结)

《Linux内核设计与实现》读书笔记 - 目录 (完结) 读完这本书回过头才发现, 第一篇笔记居然是 2012年8月发的, 将近一年半的时间才看完这本书(汗!!!). 为了方便以后查看, 做个《Linux内核设计...

你的猫大哥
2018/01/14
0
0
UNIX网络编程卷2进程间通信读书笔记汇总

UNIX网络编程卷2进程间通信读书笔记(一)—概述 http://blog.chinaunix.net/u/22935/article_52711_2.html UNIX网络编程卷2进程间通信读书笔记(二)—管道 (1) http://blog.chinaunix.ne...

长平狐
2012/09/03
247
0
【面试总结】记一次失败的 bilibili 面试总结(2)

上一篇文章能受到这样的关注度,感谢各位同学的点赞和评论,给了我很多动力继续去更新这个系列,也希望它们能够对大家有一定的帮助。蟹蟹大家。 传送门 面试总结(1):HTML布局、CSS选择器及J...

一颗赛艇🚤
03/13
0
0
2016这一年读过的那些书

1、 《超越自己》一位父亲写给儿子的116封信,刘墉的亲子哲学。 2、 《看见》柴静,弱女子不弱 3、 《崔永元-我有一事,生死与之》这本书并不是崔永元自己写的书,印象中他自己应该没有出过任...

新栋BOOK
2016/12/27
36
0

没有更多内容

加载失败,请刷新页面

加载更多

BigDecimal 去后面无用的0的方法

BigDecimal a=new BigDecimal("0.1000"); System.out.println(a.stripTrailingZeros().toPlainString());...

xiaodong16
14分钟前
4
0
JAVA--高级基础开发

[集合版双色球] 十二、双色球规则:双色球每注投注号码由6个红色球号码和1个蓝色球号码组成。红色球号码从1—33中选择;蓝色球号码从1—16中选择;请随机生成一注双色球号码。(要求同色号码...

李文杰-yaya
昨天
14
0
聊聊rocketmq broker的CONSUMER_SEND_MSG_BACK

序 本文主要研究一下rocketmq broker的CONSUMER_SEND_MSG_BACK CONSUMER_SEND_MSG_BACK rocketmq/common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java public class......

go4it
昨天
3
0
API常见接口(下)

system类 StringBuilder和StringBuffer 包装类 1.System类 (java.lang包中) 提供了大量的静态方法,可以获取与系统相关的信息或系统级操作。 常用方法: public static long currentTimeMi...

Firefly-
昨天
4
0
MySQL系列:一句SQL,MySQL是怎么工作的?

对于MySQL而言,其实分为客户端与服务端。 服务端,就是MySQL应用,当我们使用net start mysql命令启动的服务,其实就是启动了MySQL的服务端。 客户端,负责发送请求到服务端并从服务端获取数...

杨小格子
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部