ES 6 系列之三种异步 - Promise 对象
含义
Promise 是异步编程的一种解决方案,在 Promise
之前,采用的是回调函数和事件,但是会存在一些问题,像回调地狱。而在 ES6 中,提供了 Promise
对象。
Promise
简单来讲,其实就是一个容器,用来存储异步事件(例如网络请求等)。
语法上来说,Promise
是一个对象,可以获取异步操作的消息。
主要特点
- 对象状态不受外界影响。
- 一共只有三种状态:
pending
(进行中)、fulfilled
(完成)和rejected
(失败)。只受异步操作的结果,可以决定当前是哪种状态,其他任何操作都无法改变这个状态。
- 一共只有三种状态:
- 一旦状态改变,就不能再变,任何时候都可以得到这个结果。
- Promise 对象状态改变只有两种可能性,从
pending
到fulfilled
和从pending
到rejected
。
- Promise 对象状态改变只有两种可能性,从
主要缺陷
- 一旦创建会立即执行,无法中途取消。
- 如果内部不设置回调函数,外部是不能知道内部情况的。
- 当状态处于
pending
时,无法得知目前进展到哪个阶段。
基本用法
这里一般需要进行异步操作,但是为了学习方便,我们直接同步进行了。Promise
构造函数接受一个函数作为参数,该函数的参数为 resolve
和 reject
。 resolve
和 reject
是两个函数,有 JS 引擎提供,不需要自己部署。resolve
函数作用是将 Promise
的状态从 pending
变为 resolved
,并且将操作结果作为参数传递出去。reject
函数作用是将 Promise
的状态从 pending
变为 rejected
,并且将错误信息传递出去。Promise
生成实例之后,可以调用 then
方法,其中包含两个函数参数。第一个函数包含 resolved
状态的结果,第二个包含 rejected
状态结果。两个函数都是可选参数。
我们将 flag
比做异步操作,true
表示异步成功,false
表示异步失败。
1 | const promise = new Promise((resolve, reject) => { |
从上面的代码来看,flag
为 true
时,会打印 value = 操作成功
,为 false 时,打印 error = 操作失败
。
我们来看看 then
的异步。
在 Promise
创建时,就会立即执行,而 then
会在当前脚本所有同步任务执行完才会执行。
1 | const promise = new Promise((resolve, reject) => { |
实例方法
Promise.prototype.then()
Promise.prototype.then()
方法作用是为 Promise
实例添加状态改变时的回调函数。then
方法的第一个参数是 resolved
状态的回调函数,第二个参数是 rejected
状态的回调函数,它们都是可选的值,不一定必须传入。
then
方法返回的是一个新的 Promise
实例,所以可以采用链式写法。
1 | const promise = new Promise((resolve, reject) => { |
Promise.prototype.catch()
Promise.prototype.catch()
方法就是在 then
方法时 reject
的情况,用于发生错误时的回调函数。
1 | const promise = new Promise((resolve, reject) => { |
如果在 Promise
中报错,进行错误抛出,状态会变为 rejected
,就会调用 catch()
方法指定的回调函数,然后在其中处理错误。
当然,如果在运行过程中,抛出错误,也会被 catch
捕获。
1 | const promise = new Promise((resolve, reject) => { |
Promise.prototype.finally()
Promise.prototype.finally()
方法不管 Promise
对象最后状态如何,都会进行执行。
1 | const promise1 = new Promise((resolve, reject) => { |
Promise 类方法
Promise.all()
Promise.all()
方法可以将多个 Promise
实例,包装成一个新的 Promise
实例。
- 多个
Promise
中,其中一个状态不是fulfilled
,p 的结果就不会是fulfilled
1 | const promise1 = new Promise((resolve, reject) => { |
- 只要有一个状态变为
rejected
,此时第一个被reject
的实例的返回值,会被传递为promise
的回调函数。
1 | // 我们将上面的代码其中一个 resolve 修改为 reject('1') |
Promise.race()
Promise.race()
方法同样是将多个实例包装为一个新的 Promise
实例。
- 多个
Promise
时,哪一个率先改变状态,promise
的状态就跟着哪个改变。
1 | const promise1 = new Promise((resolve, reject) => { |
我们在第一个使用了 setTimeout
,进行延迟,所以会是第二个的状态先改变,输出第二个的值。
Promsie.allSettled()
Promise.allSettled()
方法,用来确定一组异步操作是否都结束了。
数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise
对象,只有数组中的 Promsie
对象状态都发生改变时,返回的 Promise
对象才发生改变。
返回的值会接收到一个数组作为参数,该数组的每一个成员对应前面数组的每个 Promise
对象。
1 | const promise1 = new Promise((resolve, reject) => { |
数组成员对象的 status
属性的值只可能是 fulfilled
或 rejected
,用来区别异步操作结果是成功(fulfilled
)还是失败(rejected
)。
如果是成功是会有 value
属性,记录成功值,如果失败,会有 reason
属性,记录失败原因。
Promise.any()
Promise.any()
方法,将一组 Promise
实例作为参数,包装成一个新的 Promise
实例并返回。
- 只要有一个变成
fulfilled
状态,新实例就会被包装成fulfilled
状态 - 如果所有参数实例都变成
rejected
状态,包装实例就会变成rejected
状态
1 | const promise1 = new Promise((resolve, reject) => { |
Promise.resolve()
Promise.resolve()
方法有四种情况。
1 | const promise = Promise.resolve('请求成功'); |
- 参数为
Promise
时,不做任何修改,直接返回这个实例。
1 | const promise = new Promise((resolve) => resolve('请求成功')); |
- 参数是
thenable
对象thenable
对象就是有then
方法的对象。Promise.resolve()
方法会将thenable
转为Promise
对象,并立即执行其中的then
方法。
1 | const thenable = { |
- 参数无
then
的对象,或不是对象的参数Promise.resolve()
方法返回一个心的 Promise 对象,状态转为resolved
。
1 | const promise = Promise.resolve('成功'); |
- 不带参数
Promise.resolve()
方法可以不传参数,直接返回一个resolved
状态的Promise
对象。
所以在希望得到一个Promise
对象,直接调用比较该方法方便。
注意,立即 resolve()
的 Promise
对象,是在本轮事件循环(event loop)的结束时执行。
1 | const promise = Promise.resolve(); |
Promise.reject()
Promise.reject()
方法返回一个新 Promise
实例,该实例状态为 rejected
。
1 | const promise = Promise.reject('出错了的Promise'); |