Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及其返回的值。是异步编程的一种解决方案。
它有三种状态,pending | fulfilled | rejected,状态变更后不可逆,有个then方法,为 Promise 实例添加状态改变时的回调函数
调用方式
|
|
大体框架
Promise的方法:
- Promise.all()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.prototype.then()
- Promise.race()
- Promise.reject()
- Promise.resolve()
可以想到Promise大体可能是这样的:
构造函数实现
- 需要记录状态,回调的执行会参考这个变量
- 需要resolve和reject去置状态, 并按次序执行回调函数
- 需要队列去存储回调函数,因为定义的时候可能还没到执行的时机
- fulfilled的回调函数调用时需要传入value
- rejected的回调函数调用时需要传入reason
|
|
then的实现
到上一步,我们都没法验证resolve是否达到我们的预期,因为成功的回调函数队列根本就是空的,我们来写下then,来指定一下我们的回调函数,这里注意指定回调函数时,如果promise的状态已经是fullfilled状态,需要直接执行回调函数,参数使用的是之前resolve传入的参数value
代码
|
|
小测一把
|
|
看到时序上有问题,但是then添加的方法确实执行了,算是成功了部分
链式调用
我们知道promise的一大功能是解决回调地狱问题,用链式来替代嵌套,所以链式调用是重点
Q: 那是不是直接在then方法里直接返回当前的promise实例就是我们想要的链式调用呢?
A: 不是的,它返回的是一个新的promise实例。
Q: why?
A: 想想实际的需求吧,我们可以要在一个异步操作之后,在它的回调函数里,又执行一个新的异步操作,我们链式调用的回调函数其实是想针对新的这个异步操作来说的。
Q: 新的实例的状态和哪个实例保持一致?
A: 如果前一个回调返回值x是一个promise实例,那链式调用返回的实例与x保持相同的状态,如果不是,那新的promise实例的状态与当前promise实例保持一致
resolveHandler 实现
鉴于对于x的类型会进行不同处理,我们不妨写一个方法专门处理一下
- 如果promise 和 x 指向相同的值, 使用 TypeError做为原因将promise拒绝。
- 如果 x 是一个promise, 采用其状态:
- 如果x是pending状态,promise必须保持pending走到x fulfilled或rejected.
- 如果x是fulfilled状态,将x的value用于fulfill promise
- 如果x是rejected状态, 将x的reason用于reject promise
- 如果x是一个对象或一个函数:
- 将 then 赋为 x.then.
- 如果在取x.then值时抛出了异常,则以这个异常做为原因将promise拒绝。
- 如果 then 是一个函数, 以x为this调用then函数, 且第一个参数是resolvePromise,第二个参数是rejectPromise,且:
- 当 resolvePromise 被以 y为参数调用, 执行 [Resolve].
- 当 rejectPromise 被以 r 为参数调用, 则以r为原因将promise拒绝。
- 如果 resolvePromise 和 rejectPromise 都被调用了,或者被调用了多次,则只第一次有效,后面的忽略。
- 如果在调用then时抛出了异常,则:
- 如果 resolvePromise 或 rejectPromise 已经被调用了,则忽略它。
- 否则, 以e为reason将 promise 拒绝。
- 如果 then不是一个函数,则 以x为值fulfill promise。
- 如果 x 不是对象也不是函数,则以x为值 fulfill promise。
按照上述的要求,我们一步步处理一下
then的链式实现
- 如果onFulfilled 或 onRejected 返回了值
x, 则执行Promise 解析流程[[Resolve]](promise2, x).- 如果
onFulfilled或onRejected抛出了异常e, 则promise2应当以e为reason被拒绝。- 如果
onFulfilled不是一个函数且promise1已经fulfilled,则promise2必须以promise1的值fulfilled.- 如果
onReject不是一个函数且promise1已经rejected, 则promise2必须以相同的reason被拒绝.
|
|
到这一步,不考虑时序的问题,上述和规范上对起来差不多了,再看看其他的方法
Promise.prototype.catch 实现
rejected时触发
Promise.prototype.finally 实现
|
|
Promise.resolve 实现
方法返回一个以给定值解析后的Promise对象。但如果这个值是个thenable(即带有then方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态(指resolved/rejected/pending/settled);如果传入的value本身就是promise对象,则该对象作为Promise.resolve方法的返回值返回;否则以该值为成功状态返回promise对象。
|
|
Promise.reject 实现
|
|
Promise.all 和 Promise.race 实现
|
|