经常会有面试官问道“如何手动实现一个符合Promise/A+规范的简易版Promise”。当然通过面试不是我们的最终目的,熟练掌握其内部实现原理才是根本。
在写代码之前,我们需要知道Promise的三种状态,即pending, resoled, rejected
。整个Promise的初始状态是pending
,然后根据后续的处理情况状态会变为resoled或者rejected
首先我们要弄清楚Promise的调用过程,在创建Promise的过程时,我们通常会new Promise(executor)
。整个Promise的构造函数接受一个executor函数,该函数接收两个参数一个是resolve,一个是reject。
但是经过简单的分析我们可以知道resolve和reject也是两个函数,并且这两个函数应该是Promise类内部帮我们实现好的。
下面我们来看Promise内部需要哪些属性:
- 我们需要一个存储当前Promise状态的status
- 一个保存Promise成功时的值,方便我们传给resolve函数
- 一个保存Promise失败时的值,方便我们传给reject函数
- 一个存储Promise成功时回调函数的数组
- 一个存储Promise失败时的回调函数的数组
private state: Status = Status.PENDING;private value: V = null;private reason: R = null;private resolvedCallbacks: IStatusFunc<V> = ;private rejectedCallbacks: IStatusFunc<R> = ;
我们也需要定义Promise内部的resolve和reject函数,这两个函数即分别执行成功和失败的回调函数。
// 将当前Promise的状态修改为resolved// 并执行resolve时的回调函数 // 将Promise的状态修改为rejected// 并执行reject时的回调函数
接下来就是实现Promise中最为重要的一步,then方法,它可以实现链式调用。我们知道在jQuery中,链式调用的方式是在方法的尾部返回jQuery对象this。但显然这种方式在Promise中行不通,因为Promise的主要任务是解决异步操作,异步操作里面的return是无效的。
我们首先想到的就是在then中返回一个Promise对象,这样返回的Promise就可以继续调用其原型链上的then方法。但此时,如果单纯的执行onFullfilled
或者onRejected
回调函数的话,此时是不会有resolve或者reject这个过程的,所以为了让Promise有链式调用的功能,我们就需要有一个专门解析onFullFilled
和onRejected
返回值得函数
/** * 解析onFullfilled或者onRejected的返回值 * @param promise2 then函数返回的新的Promise * @param x onFullfilled或者onRejected的返回值 * @param resolve 成功时的回调 * @param reject 失败时的回调 */private resolvePromisepromise2: MyPromise<V, R>, x: any, resolve: IStatusFunc<V>, reject: IStatusFunc<R>
then方法的实现也比较简单
/** * then方法 * @param onFullfilled 成功的回调函数 * @param onRejected 失败的回调函数 */thenonFullfilled: IStatusFunc<V>, onRejected?: IStatusFunc<R>