Promise是JavaScript的异步操作解决方案,它比起其它方式,比如说回调,要好很多,通过把异步任务抽象成模型,再把这个模型封装成一个对象,就是Promise对象。
所有的异步任务,都可以抽象成这么一个模型:
- 这个任务有两个阶段:未决阶段、已决阶段。
- 这个任务有三个状态:挂载状态、完成状态、失败状态。未决阶段有挂载状态,已决阶段有完成状态和失败状态。
- 这个任务有两个后续处理:完成状态后续处理、失败状态后续处理。
满足上述三点的任务,就叫它异步任务。
如何用Promise对象模拟出异步任务的这些特征呢?
下面从Promise对象的创建和使用两个方面来介绍一下。
Promise的创建
ES6为我们提供了一个构造函数Promise,专门用来创建Promise对象。
js
new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('data');
}, 300);
})
构造函数的参数是一个执行器函数,它会在创建Promise对象时立即执行。
同时执行器函数会接收两个函数作为参数,第一个参数被调用,该任务进入完成状态,如果有链式调用还会进入完成状态后续处理,第二个参数被调用,该任务进入失败状态,如果有链式调用也会进入失败状态后续处理。
Promise的使用
Promise的主要使用方式是用它提供的实例和静态方法。
一 实例方法
-
then()
可以接受两个参数,且是可选的,作为 promise 兑现和拒绝情况的回调函数,有then(onFulfilled)和then(onFulfilled, onRejected)两种调用方式。
onFulfilled函数的参数是前一个promise的兑现值,onRejected函数的参数是前一个promise的拒绝值。
ps:如果 onFulfilled 不是一个函数,则内部会被替换为一个恒等函数((x) => x),如果 onRejected 不是一个函数,则内部会被替换为一个抛出器函数((x) => { throw x; })。
then()会返回一个等效的Promise对象,新的promise的行为(称为p)取决于处理函数的执行结果,如果处理函数:
- 返回一个值:p 以该返回值作为其兑现值。
- 没有返回任何值:p 以 undefined 作为其兑现值。
- 抛出一个错误:p 抛出的错误作为其拒绝值。
- 返回一个已兑现的 Promise 对象:p 以该 Promise 的值作为其兑现值。
- 返回一个已拒绝的 Promise 对象:p 以该 Promise 的值作为其拒绝值。
- 返回另一个待定的 Promise 对象:p 保持待定状态,并在该 Promise 对象被兑现/拒绝后立即以该 Promise 的值作为其兑现/拒绝值。
-
catch()
接受一个参数,作为在 promise 被拒绝时的回调函数,使用方式是catch(onRejected),这是then(null, onRejected) 的一种简写形式。
onRejected函数的参数是前一个promise的拒绝值。
返回一个等效的Promise对象,新的promise的行为(称为p)取决于是否调用了onRejected 处理函数以及该函数的返回值:
- 如果 onRejected 没被调用(前一个 promise 已兑现),返回的 promise 与前一个 promise 具有相同的兑现值。
- 如果调用了 onRejected 处理函数(前一个 promise 已拒绝),则返回的 promise 将根据此调用的返回值进行兑现,或者使用此调用引发的错误进行拒绝。
-
finally()
接受一个参数,作为在 promise 敲定时(兑现或拒绝)的回调函数,使用方式是finally(onFinally)。
onFinally函数无参数。
返回一个等效的Promise对象,新的promise的行为(称为p)取决于 onFinally 处理函数的执行结果:
- 如果 onFinally 抛出错误或返回被拒绝的 promise,则新的 promise 将使用该值进行拒绝。
- 否则,新的 promise 将与前一个 promise 以相同的状态敲定。
二 静态方法
-
Promise.all()
接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。
当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。
-
Promise.allSettled()
将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。
当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组。
-
Promise.any()
将一个 Promise 可迭代对象作为输入,并返回一个 Promise。
当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。
-
Promise.race()
接受一个 promise 可迭代对象作为输入,并返回一个 Promise。
这个返回的 promise 会随着第一个 promise 的敲定而敲定,并返回第一个敲定的兑现值或者拒绝值。
-
Promise.reject()
返回一个已拒绝(rejected)的 Promise 对象,拒绝原因为给定的参数。
即使参数已经是一个 Promise 对象,Promise.reject() 方法也始终会将其封装在一个新的 Promise 对象中。
-
Promise.resolve()
以给定值"解决(resolve)"一个 Promise。
如果该值本身就是一个 Promise,那么该 Promise 将被返回;如果该值是一个 thenable 对象,Promise.resolve() 将调用其 then() 方法及其两个回调函数;否则,返回的 Promise 将会以该值兑现。
ps:在 Promise 成为 JavaScript 语言的一部分之前,JavaScript 生态系统已经有了多种 Promise 实现,它们都实现了 Thenable 接口,thenable 对象实现了 .then() 方法。Promise 也是 thenable 对象。
-
Promise.try()
接受一个任意类型的回调函数(无论其是同步或异步,返回结果或抛出异常),并将其结果封装成一个 Promise。
使用方式是Promise.try(func, arg1, arg2, /* ..., */ argN),返回一个 Promise,其状态可以是:
- 已兑现的,如果 func 同步地返回一个值。
- 已拒绝的,如果 func 同步地抛出一个错误。
- 异步兑现或拒绝的,如果 func 返回一个 promise。
-
Promise.withResolvers()
返回一个对象,其包含一个新的 Promise 对象和两个函数,用于解决或拒绝它,对应于传入给 Promise() 构造函数执行器的两个参数。
总结
Promise是JS中专门用来处理异步任务的对象,针对异步任务的特征,它定义了很多静态和实例方法,解决不同场景下的异步流程。