es6事件响应与处理机制 html5,读书笔记:深入理解ES6(十一)

第十一章 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)状态。分为如下两种状态:

5ec76fb35bfd28dd0ec724bbe4e3888e.png

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才会被完成。

其中,有两种情况:

ede9825cb6199f6dd482bb69d0b4de78.png

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

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

(本节完)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值