面试官你来,130行带你手写完整Promise

1,250 阅读19分钟

大家好,我是雷锋蜀黍。一直在某些面试宝典看到面试官要你手撸一个promise,今天天气这么好,不如我们来搞一搞。(PS:从未看过别人的实现,本文更像是记录一个思考的过程)

最终的代码完全符合Promise A+规范,并通过所有 promises-aplus-tests 测试用例。先上个测试通过图得瑟一下,嘿嘿嘿。

如果自己动手实现过Promise的可以直接跳到 从零开始的Promise 章节,看看我的实现,下面我们开始吧。

分析

先回想一下promise是个啥:promise是为了解决回调地狱而出现的产物,通过实例的then、catch方法进行链式调用。它本身拥有三种状态:等待、成功、失败,并且成功失败后状态无法改变。一般使用方式:

new Promise(function (resolve, reject{
    setTimeout(function ({
     resolve(1)
    }, 1000)
})
.then(function (res{
    console.log(res) // 1
    return res
})
.catch(function (res// 不会被调用
    console.log(res)
    return res
})

浏览器打印:

promise实例的打印结果
promise实例的打印结果

从中我们可以看到实例上具有[[PromiseStatus]][[PromiseValue]]两个属性,分别代表状态与值。

隐式原型上具有catch、finally、then方法。

轻微试探

先照上面分析的打个样:

let MyPromise = (function ({
    function resolve(res{
        this['[[PromiseStatus]]'] = 'fulfilled'
        this['[[PromiseValue]]'] = res
    }

    function reject(res{
        this['[[PromiseStatus]]'] = 'rejected'
        this['[[PromiseValue]]'] = res
    }
    return function (fn{
        this['[[PromiseStatus]]'] = 'pending'
        this['[[PromiseValue]]'] = undefined
        fn(resolve.bind(this), reject.bind(this)) 
    }
})()

MyPromise.prototype.then = function (fn{
    // 只有在成功状态才会调用
    if (this['[[PromiseStatus]]'] === 'fulfilled') {
        this['[[PromiseValue]]'] = fn(this['[[PromiseValue]]'])
    }
    // 返回自身 进行链式调用
    return this
}
MyPromise.prototype.catch = function (fn{
    // 只有在失败状态才会调用
    if (this['[[PromiseStatus]]'] === 'rejected') {
        this['[[PromiseValue]]'] = fn(this['[[PromiseValue]]'])
    }
    // 返回自身 进行链式调用
    return this
}

试着打印输出:

let a = new MyPromise(function (resolve, reject{
    setTimeout(function ({
        resolve(1)
    }, 1000)
}).then(function (res{
    console.log(res)
    return 2
}).catch(function (res{
    console.log(res)
    return 3
})
console.log(a)
不具备异步能力的输出结果
不具备异步能力的输出结果

事情不简单

emmm,把异步的问题忘记了,在setTimeout期间状态一直是pending,所以直接调用then是无效的。思路应该是把这些then中的方法进行存储,在resolve结束时进行调用。

我们创建个属性进行链式函数的存储,需要注意的是存在成功和失败两种状态。

let MyPromise = (function ({
    function resolve(res{
        this['[[PromiseStatus]]'] = 'fulfilled'
        this['[[PromiseValue]]'] = res
       // 模拟异步 并保证接收到所有then方法后执行
        setTimeout(() => {      
         // 遍历finishArr并链式执行
            while (this.asyncArr.finishArr.length > 0) {
                this.asyncArr.finishArr.shift()()
            }
        }, 0);
        // 干掉永远不可能执行的方法
        this.asyncArr.errorArr = []
    }

    function reject(res{
        this['[[PromiseStatus]]'] = 'rejected'
        this['[[PromiseValue]]'] = res
       setTimeout(() => {
       // 遍历errorArr并链式执行
            while (this.asyncArr.errorArr.length > 0) {
                this.asyncArr.errorArr.shift()()
            }
        }, 0);
        // 干掉永远不可能执行的方法
        this.asyncArr.finishArr = []
    }
    return function (fn{
        this['[[PromiseStatus]]'] = 'pending'
        this['[[PromiseValue]]'] = undefined
        this.asyncArr = {       // 保存链式调用的方法
            finishArr: [],
            errorArr: []
        }
        fn(resolve.bind(this), reject.bind(this))
    }
})()

MyPromise.prototype.then = function (fn{
    // 失败时直接返回 等待和成功都要压入数组中
    ifthis['[[PromiseStatus]]'] === 'rejected')  return this
    this.asyncArr.finishArr.push( ()=> {
        this['[[PromiseValue]]'] = fn(this['[[PromiseValue]]'])
    })
    // 返回自身 进行链式调用
    return this
}
MyPromise.prototype.catch = function (fn{
    ifthis['[[PromiseStatus]]'] === 'fulfilled')  return this
    this.asyncArr.errorArr.push( ()=> {
        this['[[PromiseValue]]'] = fn(this['[[PromiseValue]]'])
    })
    // 返回自身 进行链式调用
    return this
}

欧凯~这样就解决了异步的问题,也完全满足我们常用的几个功能。但是大家觉得这就结束了吗?不,这只是开始,还是个错误的开始。

大错特错

下面我们一起来总结下上面的代码在逻辑上存在哪些错误

1.promise的状态无法被“改变”

可能有人就疑惑了,promise的状态本来就是不能被改变的,这没有错啊。那请你来看下面这段代码:

let a = new Promise(function (resolve, reject) {
        reject(1)
    })
    .catch(function (res) {
        console.log(res)
        return 3
    })
    .then(function (res) {
        console.log(res)
    })
    console.log(a)  // type: resolved    val: undefined

你会发现a的状态从reject变为了resolved,你是否会动摇对promise的认知呢,就觉得别人说的什么promise不能改变状态都是扯淡,能变得。

切勿听风是雨,自己动手试一下才会真的明白。 then方法返回的并不是当前对象自身,而是一个全新的Promise。 promise执行示例图

2.鸡蛋全放一个篮子里

现在我们将所有的then、catch方法都存放到了第一个promise的属性上,那如果按照上一条的改进意见,每次都返回一个全新的promise,那这种方式是否可行呢?答案我想是可以的,但是这样并不好,会造成头重脚轻,首个promise对象与其他promise对象大不一样的感觉,所以我想正确的数据结构应该是这样的。

promise对象结构 通过next进行链式调用,每个promise仅保存下一个所指向的promise,并且当前的Promise状态决定下一个Promise调用resolve还是reject,再通过这些方法来决定当前promise的状态。从此无限套娃~ 同时这样你也不需要两个数组来对成功的方法与错误的方法进行分离存储,全部都是用next指向,这和Promise的概念也是相同的,Promise的状态仅会被一个改变状态函数所影响,其余的都将会忽略。

从零开始的Promise

下面才是本篇文章正真的开始,根据以上总结出的经验,我们来实现一个完整的并完全符合Promise A+规范的Promise。

最靓的仔
最靓的仔

我们先来总览一下MDN上描述的Promise方法:

静态方法:

Promise.all(iterable)

Promise.race(iterable)

Promise.reject(reason)

Promise.resolve(value)

实例方法:

Promise.prototype.catch(onReject)

Promise.prototype.then(onFulfilled,onRejected)

Promise.prototype.finally

具体细节就不赘述了,不太清楚的小伙伴请自行去mdn上进行学习后再回来看具体实现,下面我们开始吧。

Promise构造函数

人狠话不多,先上代码再讲解

let MyPromise = (function () {
    function resolve(res) {
        // 如果存在状态则直接返回
        if (this['[[PromiseStatus]]'] != 'pending') return  
        // 如果接收到的值是自己本身则报错
        if (res === this) {
            throw new Error(
            'TypeError: Chaining cycle detected for promise #<Promise>')
        }
        // 如果res 是一个promise对象 则等待其值然后返回
        this['[[PromiseStatus]]'] = 'fulfilled'
        this['[[PromiseValue]]'] = res

        // promise 是一个宏任务  使用 setTimeout 进行模拟
        setTimeout(() => {
            if (this.next) {
                this.next()
                delete this.next     // 解除关联关系 防止无法被垃圾回收器回收
            }
        }, 0)
    }
    function reject(res) {
        // 如果存在状态则直接返回
        if (this['[[PromiseStatus]]'] != 'pending') return  
        this['[[PromiseStatus]]'] = 'rejected'
        this['[[PromiseValue]]'] = res
        setTimeout(() => {
            // 如果有下一个promise则传值,如果没有则直接报错
            if (this.next) {
                this.next()         //  将会创建下一个promise 在then方法中进行定义
                delete this.next     // 解除关联关系 防止无法被垃圾回收器回收
            } else {
                throw new Error(res)
            }
        }, 0)
    }
    return function (fn) {
        this['[[PromiseStatus]]'] = 'pending'   // 保存当前promise状态
        this['[[PromiseValue]]'] = undefined    // 保存当前promise的值
        this.next = null                        // 创建下一个promise
        // 保存所有的finally方法 当改promise当用完前运行内部所有方法
        this.finallyArr = []   
        // 调用用户传入的函数,并将resolve与reject回传
        fn(resolve.bind(this), reject.bind(this))   
    }
})()

特别说明

这里跟大家强调说明一下,使用setTimeout不仅仅是单纯为了模仿异步效果,而是这样将调用next方法变为一个宏任务,可以确保在链式调用时,then方法之后进行执行。

这里将当传入的参数为promise的处理和finally方法的处理暂时去除了,等下面涉及到时再和大家单独说明。

Promise.prototype.then

该方法是整个Promise的核心,并且Promise A+规范规定的也是该方法,下面我们继续先上代码,我会把注释写全,再和大家讨论实现思路。

MyPromise.prototype.then = function (onFulfilled, onRejected) {
    let _self = this    // 记录前一个promise
    let promise = new MyPromise(function (resolve, reject) {
        // 将方法保存下来 在上一个的next中进行触发
        _self.next = () => {
            // 上一个promise的状态 决定调用哪个函数方法
            // 是成功的 则调用 onFulfilled
            if (_self['[[PromiseStatus]]'] == 'fulfilled') { 
                // 如果onFulfilled不存在 则将上一个的值直接传递给当前全新的promise
                if (typeof onFulfilled !== 'function') {
                    resolve.call(this, _self['[[PromiseValue]]'])
                }
                // 当前promise的状态由 执行的方法决定
                try {
                    // 将上一个的值进行回传 
                    let data = onFulfilled(_self['[[PromiseValue]]']) 
                    resolve.call(this, data)   // 成功 则调用 resolve方法
                } catch (error) {
                    reject.call(this, error)   // 失败则调用 reject
                }
            }
            // 是失败的 则调用 onRejected
            else if (_self['[[PromiseStatus]]'] == 'rejected') { 
                 // 如果没有错误处理方法则直接报错 当前的值
                if (typeof onRejected !== 'function') {
                    reject.call(this, _self['[[PromiseValue]]'])
                } 
                // 当前promise的状态由 执行的方法决定
                try {
                    let data = onRejected(_self['[[PromiseValue]]'])
                    resolve.call(this, data)   // 成功 则调用 resolve方法
                } catch (error) {
                    reject.call(this, error)   // 失败则调用 reject
                }
            }
            // 如果是等待状态 就空
        }
    })
    // 返回一个全新的promise
    return promise
}
}

上面的代码充斥着高阶函数和call、apply,可能不太好理解,下面和大家一起探讨一下 首先思路和大错特错那一章节中是一样的,即:

当前Promise的执行resolve、reject是由上一个Promise决定的

当前Promise的状态,是由该Promise的resolve、reject决定的

特别说明

我们在新建的Promise中并未去触发改变该状态的函数,而是将其保存在了上一个Promise的next属性中,当上一个Promise触发resolve方法时再去触发,这样就完成了异步的状态改变。

下面拿一个示例说说整个Promise发生的流程:

new MyPromise(function (resolve) {
    setTimeout(() => {
        resolve(42)
    }, 1000);
})
.then(res =>{
    console.log(res)
})

第一步:创建一个新的Promise,将一个匿名方法传入,将会在构造函数中被调用,等待一秒后会去触发resolve方法

...
fn(resolve.bind(this), reject.bind(this))

第二步:调用首个Promise的then方法,创建一个全新的等待状态的Promise2,请将改变其状态的方法存在Promise1next属性中

...
let promise = new MyPromise(function (resolve, reject) {
    _self.next = () => {
        ...
    }
})
return promise

第三步:第一步的匿名函数setTimeout触发resolve方法,改变了首个Promise的状态和值,同时会去检查是否存在下一个Promise,如果存在则执行

...
if (this.next) {
    this.next()
    delete this.next     // 解除关联关系 防止无法被垃圾回收器回收
}
...

第四步:next方法带着首个Promise的状态来了,改变Promise2的状态

...
// 上一个promise的状态 决定调用哪个函数方法
// 是成功的 则调用 onFulfilled
if (_self['[[PromiseStatus]]'] == 'fulfilled') {      
    // 如果onFulfilled不存在 则将现有的值传递给下一个全新的promise
    if (typeof onFulfilled !== 'function'){
         resolve.call(this, _self['[[PromiseValue]]'])
    }
    // 当前promise的状态由 执行的方法决定
    // 将上一个的值进行回传 
    try {
        let data = onFulfilled(_self['[[PromiseValue]]'])   
        resolve.call(this, data)   // 成功 则调用 resolve方法
    } catch (error) {
        reject.call(this, error)   // 失败则调用 reject
    }
}
...

第五步: Promise2resolvereject再次触发next方法,以此往复


我们再来看看这两句代码:

...
if (typeof onFulfilled !== 'function') {
    resolve.call(this, _self['[[PromiseValue]]'])
}
...
if (typeof onRejected !== 'function') {
    reject.call(this, _self['[[PromiseValue]]'])
}
...

但凡遇到空的then方法,将会直接将上一个Promise的状态和值复制,能够继续向下传递,就像这样子:

new MyPromise(function (resolve) {
    resolve(42)
})
.then()
.then()
.then(res =>{
    console.log(res)    // 42
})

对于空的Promise.then()根本无需理会,同样返回一个全新的空Promise即可

我们再回过头将reslove方法进行扩充,如果传入的值是Promise对象呢?我们将等待其完成然后再进行赋值操作。

...
// 如果res 是一个promise对象 则等待其值然后返回
if (res instanceof MyPromise) {
    res.then(val => {
        this['[[PromiseStatus]]'] = 'fulfilled'
        this['[[PromiseValue]]'] = val
    }, err => {
        this['[[PromiseStatus]]'] = 'rejected'
        this['[[PromiseValue]]'] = err
    })
} 
else {
    this['[[PromiseStatus]]'] = 'fulfilled'
    this['[[PromiseValue]]'] = res
}
...

then方法这是整个Promise实现最难的地方,大家要是没理解的话可以自己动手跑一下,我会将完整实现全部贴在最后。

Promise.prototype.catch

实现了then方法后,你会发现其实catch方法只是then方法的阉割版,即没有了成功的回调方法,只有失败的方法。实现代码很简单:

MyPromise.prototype.catch = function (onRejected) {
    // 直接调用then方法 并返回then返回的 promise
    return MyPromise.prototype.then.call(this, null, onRejected)
}

没错,直接调then方法即可

Promise.prototype.finally

该方法定义了无论Promise失败与否,都将会执行的函数。之前实现的thencatch方法都是和Promise的状态与值挂钩的, 而finally方法不是,只是单纯的在一个Promise调用结束后触发的方法,甚至它连回调参数也没有。所以我们重新设置一个对象参数来存储finally的参数。

return function (fn) {
    // 保存当前promise状态
    this['[[PromiseStatus]]'] = 'pending'   
    // 保存当前promise的值
    this['[[PromiseValue]]'] = undefined    
    // 指向下一个pomise
    this.next = null          
    // 保存所有的finally方法 当改promise当用完前运行内部所有方法
=>  this.finallyArr = []  
    // 调用用户传入的函数,并将resolve与reject回传
    fn(resolve.bind(this), reject.bind(this))  
}

finally方法中进行添加

MyPromise.prototype.finally = function (onFinally) {
    // 链式调用 但是不会返回新的promise对象
    this.finallyArr.push(onFinally)
    return this
}

同时注意,finally返回的是自身,与then、catch是不同的。 现在方法都存储起来了,只要在该Promise执行后调用就可以了,resolve函数添加代码如下:

...
setTimeout(() => {
    // 遍历finishArr并链式执行
    // 遍历执行finally 方法
    while (this.finallyArr.length > 0) {
        this.finallyArr.shift()()
    }
    delete this.finallyArr
    if (this.next) {
        this.next()
        delete this.next     // 解除关联关系 防止无法被垃圾回收器回收
    }
}, 0)
...

并且当全部执行后就把该属性删除,这样在浏览器中打印出来就和原生的一模一样了,哈哈哈哈哈哈哈。

机灵鬼 到此,Promise的实例方法全部完成,我们来看看静态方法吧。

Promise.resolve

它返回一个成功状态的Promise,虽然我感觉它和我在闭包内实现的resolve方法差不多,但是我没有想到一个很好的办法来进行整合,如果有小伙伴想到的话请第一时间告知我!~ 代码实现很简单。

MyPromise.resolve = function (value) {
    // 如果是promise类型直接返回
    if (value instanceof MyPromise) return value
    return new MyPromise(function (resolve) {
        resolve(value)
    })
}

Promise.reject

它与MyPromise.resolve是一样的道理。

MyPromise.reject = function (value) {
    // 如果是promise类型直接返回
    if (value instanceof MyPromise) return value
    return new MyPromise(function (resolve, reject) {
        reject(value)
    })
}

MyPromise.race

该方法的定义是但凡接收到的类数组参数中有一个参数成功了就直接返回包含该参数的Promise,失败同理,直接上代码:

MyPromise.race = function (arr) {
    let promise = new MyPromise(function (resolve, reject) {
        for (let i = 0; i < arr.length; i++) {
            //  如果是promise 则使用then 进行监听 谁先完成或者失败就直接改变状态
            if (arr[i] instanceof MyPromise) {
                arr[i].then(function (res) {
                    resolve(res)
                }, function (err) {
                    reject(err)
                })
            } else {
                 // 如果不是promise 则直接返回结果
                resolve(arr[i])
            }
        }
    })
    return promise
}

在现在的Promise实现下,去异步监听值得变化变的异常简单,从而能够判断谁是第一个完成或失败的,从而返回它的状态。

Promise.all

该方法与race相反,所以类数组中的参数成功了才会返回一个包含它们结果的Promise,失败则直接返回错误消息。实现起来相较race稍难一点,需要判断当前类数组中的参数是否全部完成,但是在then方法下都信手捏来。

MyPromise.all = function (arr) {
    let promise = new MyPromise(function (resolve, reject) {
        let result = [] // 将结果保存
        let start = 0,  // 开始异步的数量 
            finish = 0      // 完成异步的数量
        for (let i = 0; i < arr.length; i++) {
            // 如果是promise 则使用then 进行监听
            if (arr[i] instanceof MyPromise) {
                ++start // 记录当前开始了多少个promise
                // 使用then就会被挂起监听
                arr[i].then(res => {
                    ++finish    // 记录当前完成了多少个promise
                    result[i] = res
                    // 全部完成则返回成功状态与数据
                    if (start == finish) resolve(result) 
                }, err => {
                    reject(err)     // 错了就直接返回
                })
            } else {
                result[i] = arr[i]
            }
        }
        // 如果没有异步方法 则直接返回结果
        if (!start) resolve(result)
    })
    return promise
}

通过在then方法中对startfinish的对比,从而能够知道当前完成的Promise是否是最后一个,进而返回全部结果。

完整实现代码

到这里就将整个Promise实现啦,同时我个人也使用promises-aplus-tests进行了测试,符合全部规范,大家可以安心食用。


let MyPromise = (function () {
    function resolve(res) {
        if (this['[[PromiseStatus]]'] != 'pending') return  // 如果存在状态则直接返回
        // 如果接收到的值是自己本身则报错
        if (res === this) {
            throw new Error('TypeError: Chaining cycle detected for promise #<Promise>')
        }
        // 如果res 是一个promise对象 则等待其值然后返回
        if (res instanceof MyPromise) {
            res.then(val => {
                this['[[PromiseStatus]]'] = 'fulfilled'
                this['[[PromiseValue]]'] = val
            }, err => {
                this['[[PromiseStatus]]'] = 'rejected'
                this['[[PromiseValue]]'] = err
            })
        } else {
            this['[[PromiseStatus]]'] = 'fulfilled'
            this['[[PromiseValue]]'] = res
        }

        // promise 是一个宏任务  使用 setTimeout 进行模拟
        setTimeout(() => {
            // 遍历finishArr并链式执行
            // 遍历执行finally 方法
            while (this.finallyArr.length > 0) {
                this.finallyArr.shift()()
            }
            delete this.finallyArr
            if (this.next) {
                this.next()
                delete this.next     // 解除关联关系 防止无法被垃圾回收器回收
            }
        }, 0)
    }

    function reject(res) {
        if (this['[[PromiseStatus]]'] != 'pending') return  // 如果存在状态则直接返回
        this['[[PromiseStatus]]'] = 'rejected'
        this['[[PromiseValue]]'] = res
        setTimeout(() => {
            // 遍历执行finally 方法
            while (this.finallyArr.length > 0) {
                this.finallyArr.shift()()
            }
            delete this.finallyArr
            // 如果有下一个promise则传值,如果没有则直接报错
            if (this.next) {
                this.next()
                delete this.next     // 解除关联关系 防止无法被垃圾回收器回收
            } else {
                throw new Error(res)
            }
        }, 0)
    }
    return function (fn) {
        this['[[PromiseStatus]]'] = 'pending'
        this['[[PromiseValue]]'] = undefined
        this.next = null
        this.finallyArr = []   // 保存所有的finally方法 当改promise当用完前运行内部所有方法
        fn(resolve.bind(this), reject.bind(this))
    }
})()

MyPromise.resolve = function (value) {
    // 如果是promise类型直接返回
    if (value instanceof MyPromise) return value
    return new MyPromise(function (resolve) {
        resolve(value)
    })
}

MyPromise.reject = function (value) {
    // 如果是promise类型直接返回
    if (value instanceof MyPromise) return value
    return new MyPromise(function (resolve, reject) {
        reject(value)
    })
}

MyPromise.all = function (arr) {
    let promise = new MyPromise(function (resolve, reject) {
        let result = [] // 将结果保存
        let start = 0,  // 开始异步数量 
            finish = 0      // 完成异步的数量
        for (let i = 0; i < arr.length; i++) {
            // 如果是promise 则使用then 进行监听
            if (arr[i] instanceof MyPromise) {
                ++start // 记录当前开始了多少个promise
                // 使用then就会被挂起监听
                arr[i].then(res => {
                    ++finish    // 记录当前完成了多少个promise
                    result[i] = res
                    if (start == finish) resolve(result) // 全部完成则返回成功状态与数据
                }, err => {
                    reject(err)     // 错了就直接返回
                })
            } else {
                result[i] = arr[i]
            }
        }
        // 如果没有异步方法 则直接返回结果
        if (!start) resolve(result)
    })
    return promise
}

MyPromise.race = function (arr) {
    let promise = new MyPromise(function (resolve, reject) {
        for (let i = 0; i < arr.length; i++) {
            //  如果是promise 则使用then 进行监听 谁先完成或者失败就直接改变状态
            if (arr[i] instanceof MyPromise) {
                arr[i].then(function (res) {
                    resolve(res)
                }, function (err) {
                    reject(err)
                })
            } else {
                 // 如果不是promise 则直接返回结果
                resolve(arr[i])
            }
        }
    })
    return promise
}

MyPromise.prototype.then = function (onFulfilled, onRejected) {
    let _self = this    // 记录前一个promise
    let promise = new MyPromise(function (resolve, reject) {
        // 将方法保存下来 在上一个的next中进行改变状态操作
        _self.next = () => {
            // 上一个promise的状态 决定调用哪个函数方法
            // 当前是成功的 则调用 onFulfilled
            if (_self['[[PromiseStatus]]'] == 'fulfilled') {      
                // 如果onFulfilled不存在 则将现有的值传递给下一个全新的promise
                if (typeof onFulfilled !== 'function') {
                    resolve.call(this, _self['[[PromiseValue]]'])
                }
                // 当前promise的状态由 执行的方法决定
                try {
                    let data = onFulfilled(_self['[[PromiseValue]]'])
                    resolve.call(this, data)   // 成功 则调用 resolve方法
                } catch (error) {
                    reject.call(this, error)   // 失败则调用 reject
                }
            }
            // 当前是失败的 则调用 onRejected
            else if (_self['[[PromiseStatus]]'] == 'rejected') {  
                // 如果没有错误处理方法则直接报错 当前的值
                if (typeof onRejected !== 'function') {
                    reject.call(this, _self['[[PromiseValue]]'])  
                }
                // 当前promise的状态由 执行的方法决定
                try {
                    let data = onRejected(_self['[[PromiseValue]]'])
                    resolve.call(this, data)   // 成功 则调用 resolve方法
                } catch (error) {
                    reject.call(this, error)   // 失败则调用 reject
                }
            }
            // 如果是等待状态 就空
        }
    })
    // 需要返回一个全新的promise 并且这个promise就是当前处理的这个
    return promise
}

MyPromise.prototype.catch = function (onRejected) {
    // 直接调用then方法 并返回then返回的 promise
    return MyPromise.prototype.then.call(this, null, onRejected)
}

MyPromise.prototype.finally = function (onFinally) {
    // 链式调用 但是不会返回新的promise对象
    this.finallyArr.push(onFinally)
    return this
}

Promise.deferred = Promise.defer = function () {
    var dfd = {}
    dfd.promise = new Promise(function (resolve, reject) {
        dfd.resolve = resolve
        dfd.reject = reject
    })
    return dfd
}

module.exports = Promise

Promise.deferred是给测试提供的接口,无视。

结语

我还记得那是一个晴朗的早晨,外面天气很好,我看到一个题目姚手撸一个Promise,我说这有什么难的,我来。 不曾想,实现加上写文章整整花费了一个礼拜的业余时间,着实有点难顶。在此厚脸皮的跟大家要个,你看成吗?

我做完以后去网上查阅了一下,大家好像都用数组对回调方法进行存储,如果我一开始也去看这一类的文章再自己动手,可能脑海里也会习惯性的用已知方法解决。其实我想说就是,解决问题有时候不必一味的去模仿、照搬,静下来自己想一想,也许你会有你自己的答案。