ES6 promise

Posted aizzz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES6 promise相关的知识,希望对你有一定的参考价值。

异步编程(js中)

JS 引擎是基于单线程事件循环地概念构建的,JS引擎同一时刻只能执行一个代码块,所以需要跟踪即将运行的代码块,

那些代码被放在一个任务队列中,每当一段代码准备执行时,都会被加入任务队列,每当javascript引擎中的一段代码

结束执行时,事件循环会执行队列中的下一个任务,它是JavaScript引擎的一段程序,负责监控代码执行并管理任务队列。

任务队列是按加入顺序执行的,从第一个到最后一个。

 

事件模型

用户点击按钮或按下按键会触发类似onclick这样的事件,它会向任务队列添加一个新任务来响应用户的操作,这是JavaScript

中最基础的异步编程形式,直到事件触发才会执行事件处理程序,且执行上下文与定义时的相同。

技术分享图片必须保证事件在添加事件处理程序之后触发,适用于简单的用户交互

 

回调模式

 技术分享图片回调模式中被调用的函数通过参数传入

错误优先回调风格,readFile() 函数读取磁盘上的某个文件,读取结束后执行回调函数,如果出现错误,错误对象被赋值给回调函数的err参数

如果一切正常,文件内容以字符串形式赋值给contents参数

由于使用了回调模式,也就是说,readFile()函数立即执行,当读取磁盘文件会暂停执行, 也就是说,调用readFile()后,

输出Hi语句立即执行,当readFile()结束执行,会向任务队列末尾添加一个新任务,包含回调函数和相应参数,当前面

的任务都执行完,才执行该任务

技术分享图片

这段代码中,成功调用readFile() 后会执行另一个writeFile() 函数的异步调用,通过相同模式检查err是否存在,

当readFile()执行完成,向任务队列添加一个任务,如果没有错误产生,则执行writeFile()函数,当writeFile()

函数执行结束后也会向任务队列添加一个任务。

缺点:嵌套了太多回调函数,陷入回调地狱

 

Promise基础知识

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

技术分享图片

 

readFile() 不会立即开始读取文件,函数会先返回一个表示异步读取操作的Promise对象,未来对这个对象的操作完全取决于Promise的生命周期

 

(1)Promise的生命周期

每个Promise的生命周期,先是处于进行中(pending)的状态,此时操作未完成,所以它是未处理的,一旦异步操作执行结束,Promise则变为已处理的,

在之前实例中,当readFile()返回Promise时它变为penging状态,操作结束后,Promise可能会进入到以下两个状态之一

    · Fulfilled :Promise异步操作成功完成

    · Rejected: 由于程序错误或其他原因,Promise异步操作未能成功完成

内部属性[[PromiseState]] 被用来表示Promise的3种状态,‘pending‘, ‘fulfilled‘, ‘rejected‘ 

这个属性不暴露在Promise对象上,不能通过编程检测Promise状态,只有当Promise状态改变时, 通过then()方法采取行动

  所有Promise都有then()方法,接受两个参数,一个是当Promise的状态为fulfilled时要调用的函数,与异步操作相关的附加数据都会

传递给这个完成函数,第二个是当promise的状态变为rejected时要调用的函数,所有与失败状态相关的附加数据都会传递给这个拒绝函数

  如果一个对象实现了then() 方法,我们称之为thenable对象,所有Promise对象都是thenable对象,但反过来不一定

技术分享图片

 

上述三个then()调用同一个Promise,第一个同时监听成功和失败,第二个只监听了成功,失败不处理,第三个只监听了失败,成功不处理

 

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

技术分享图片两个等价

 

 

 技术分享图片

一个完成处理程序被调用时向同一个Promise添加了另一个完成处理程序,此时Promise已经完成

所有新的 处理程序会被添加到任务队列,当前面任务完成才调用

每次调用then或者catch方法都会创建一个新任务,当Promise被解决时执行(resolved)

 

创建未完成的Promise

用Promise构造函数创建新的Promise,构造函数接收一个参数,包含初始化Promise代码的执行器函数,

执行器接收两个参数,一个resolve()函数和一个reject() 函数,执行器成功完成时调用resolve() ,失败调用reject()

技术分享图片

调用readFile() 方法时,执行器会立即执行,在执行器中,无论是调用resolve() 还是 reject() 都会向任务队列添加一个任务来解决这个Promise

技术分享图片

完成处理程序和拒绝处理程序总是在执行器完成后被添加到任务队列的末尾。

 

创建已处理的Promise,Promise.resolve() 返回一个完成态的Promise

技术分享图片

 

如果向Promise.resolve() 方法或者Promise.reject() 方法传入一个Promise,那这个Promise会被直接返回

 

非Promise的Thenable对象

技术分享图片

技术分享图片

Promise.resolve() 调用的是thenable.then(),由于then() 方法内部调用了resolve(42), 因此Thenable对象的状态是已完成

新创建的已完成态p1 从Thenable对象接受传入的值42,p1的完成处理程序将42赋值给value

 

执行器错误

如果执行器内部抛出一个错误,那Promise的拒绝处理程序就会被调用

技术分享图片

执行器会捕获所有抛出的错误,但只有当拒绝处理程序存在时,才会记录执行器抛出的错误,否则错误会忽略

 

全局的Promise拒绝处理

技术分享图片

没有拒绝处理程序的情况下拒绝一个Promise,不会提示失败信息,

很难检测一个Promise什么时候被处理

 

串联Promise

每次调用then() 方法或catch() 方法实际上创建并返回了另一个Promise,

只有当第一个Promise完成或被拒绝后,第二个才会被解决

技术分享图片

捕获错误

技术分享图片

 

Promise链的返回值

可以给下游Promise传递数据

在Promise链中返回Promise

技术分享图片

 

Promise p1 被解决后传入42,同时返回一个已解决状态的p2,由于p2已经被完成

因此第二个解决程序被调用,如果p2被拒绝,则调用拒绝处理程序

注意:第二个完成处理程序被添加到了第三个Promise而不是p2!

 在完成或拒绝处理程序中返回Thenable对象不会改变Promise执行器的执行时机,

返回Thenable对象仅允许你为这些Promise结果定义额外的响应

 

在完成处理程序中创建新的Promise可以推迟完成处理程序的执行

技术分享图片

 

在p1的完成处理程序中创建了一个新的Promise,直到p2被完成才会

执行第二个完成处理程序

 

Promise.all()

只接收一个参数并返回一个Promise,该参数是含有多个受监视的Promise的可迭代对象(例如数组)

只有当可迭代对象中所有Promise都被解决后返回的Promise才会被解决,

只有当可迭代对象中所有的Promise对象都被完成后返回的Promise才会被完成

技术分享图片

 

如上,当全部完成,p4才被完成

所有传入Promise.all() 的Promise只要有一个被拒绝,那么返回的Promise没等所有Promise完成都立即被拒绝

技术分享图片

p2被拒绝并传入值43,没等p1或p3结束执行,p4的拒绝处理程序就调用了(p1和p3的执行过程会结束,只是p4没有等待)

 

Promise.race()

也接受包含多个受监视的Promise的可迭代对象作为唯一参数并返回一个Promise

但只要有一个Promise被解决返回的Promise就被解决,无须等到所有Promise都被完成,

一旦数组中某个Promise被完成,Promise.race() 会像Promise.all() 一样返回一个特定的Promise对象

传给Promise.race() 方法的Promise会进行竞选,以决出哪一个先被解决,如果先解决的是已拒绝Promise,则返回已拒绝Promise

 

以上是关于ES6 promise的主要内容,如果未能解决你的问题,请参考以下文章

ES6中的Promise

ES6的Promise详解

ES6 中Promise 使用

Web | ES6的异步编程

ES6异步操作Promise

ES6 - Promise 对象