面試官你來,130行帶你手寫完整Promise

你們好,我是雷鋒蜀黍。一直在某些面試寶典看到面試官要你手擼一個promise,今每天氣這麼好,不如咱們來搞一搞。(PS:從未看過別人的實現,本文更像是記錄一個思考的過程)web

最終的代碼徹底符合Promise A+規範,並經過全部 promises-aplus-tests 測試用例。先上個測試經過圖得瑟一下,嘿嘿嘿。面試

若是本身動手實現過Promise的能夠直接跳到 從零開始的Promise 章節,看看個人實現,下面咱們開始吧。數組

分析

先回想一下promise是個啥:promise是爲了解決回調地獄而出現的產物,經過實例的then、catch方法進行鏈式調用。它自己擁有三種狀態:等待、成功、失敗,而且成功失敗後狀態沒法改變。通常使用方式:promise

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方法。閉包

輕微試探

先照上面分析的打個樣:app

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結束時進行調用。async

咱們建立個屬性進行鏈式函數的存儲,須要注意的是存在成功和失敗兩種狀態。

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,我說這有什麼難的,我來。 未曾想,實現加上寫文章整整花費了一個禮拜的業餘時間,着實有點難頂。在此厚臉皮的跟你們要個,你當作嗎?

我作完之後去網上查閱了一下,你們好像都用數組對回調方法進行存儲,若是我一開始也去看這一類的文章再本身動手,可能腦海裏也會習慣性的用已知方法解決。其實我想說就是,解決問題有時候沒必要一味的去模仿、照搬,靜下來本身想想,也許你會有你本身的答案。

相關文章
相關標籤/搜索