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'); |