1. 程式人生 > >理解Promise 實現原理

理解Promise 實現原理

實現基本呼叫

/**
 * @desc 自定義promiseL類,模擬實現promise物件
 * @param {function} excutor 使用者在初始化Promise物件時傳入的函式
 */
function PromiseL (excutor) {
    let self = this
    self.status = 'padding' //預設等待狀態
    self.value = undefined //狀態成功時的value
    self.reason = undefined //狀態為失敗時的error 資訊
    //因為是非同步呼叫 所以需要把callback快取起來
self.resolvedCallBackArr = [] //成功的回撥函式 self.rejectedCallBackArr = [] //失敗的回撥函式 /** * @desc 使用者觸發成功的時候的回到 * @param {all} value 使用者傳入的引數 未知型別 * */ function resolve (value) { //如果函式執行成功,則修改狀態為成功, if (self.status == 'padding') { self.value = value self.status = 'resolved'
//遍歷呼叫回撥函式 self.resolvedCallBackArr.forEach(callback => callback(self.value)) } } /** * @desc 使用者觸發rejcet時呼叫的函式 * @param {[type]} reason 錯誤資訊 未知 * @return {[type]} [description] */ function reject (reason) { //如果狀態失敗 更改狀態和賦值
if (self.status == 'padding') { self.reason = reason self.status = 'rejected' self.rejectedCallBackArr.forEach(callback => callback(self.reason)) } } //只要有錯誤 就走tra catch //使用者第一次傳入的函式同步執行 try { excutor(resolve, reject) } catch (e) { reject(e) } // console.log(excutor) } /** * @desc 在例項上擴充套件then方法 * @param {function} onFulfiled 使用者傳入的成功會調函式 * @param {function} onRejected 使用者傳入的失敗回撥函式 * 方法思路: * 1.呼叫的時候如果是成功狀態,則呼叫onFulfiled成功狀態函式,並將引數傳入 * 2.呼叫的時候如果是失敗狀態,則呼叫onRejected成功狀態函式,並將引數傳入 * 3.呼叫的時候如果是等待狀態,則將傳入的函式快取進入程式池,後期使用者主動觸發的時候呼叫 * @return {[type]} [description] */ PromiseL.prototype.then = function (onFulfiled, onRejected) { let self = this //根據狀態呼叫函式 if (self.status == 'resolved') { onFulfiled(this.value) } if (self.status == 'rejected') { onRejected(self.reason) } //如果是非同步 先將回調函式快取 if (self.status == 'padding') { self.resolvedCallBackArr.push(onFulfiled) self.rejectedCallBackArr.push(onRejected) } }

實現錯誤處理,返回一個 PromiseL 物件例項

捕捉錯誤處理不是和理解,寫出來也感覺不對,暫時先擱置,後期考證

/**
 * @desc 自定義promiseL類,模擬實現promise物件
 * @param {function} excutor 使用者在初始化Promise物件時傳入的函式
 */
function PromiseL (excutor) {
    let self = this
    self.status = 'padding' //預設等待狀態
    self.value = undefined
    self.reason = undefined
    //因為是非同步呼叫 所以需要把callback快取起來
    self.resolvedCallBackArr = [] //成功的回撥函式
    self.rejectedCallBackArr = [] //失敗的回撥函式

    /**
     * @desc 使用者觸發成功的時候的回到
     * @param  {all} value 使用者傳入的引數 未知型別
     * 
     */
    function resolve (value) {
        //如果函式執行成功,則修改狀態為成功,
        if (self.status == 'padding') {
            self.value = value
            self.status = 'resolved'

            //遍歷呼叫回撥函式
            self.resolvedCallBackArr.forEach(callback => callback(self.value))
        }
    }

    /**
     * @desc 使用者觸發rejcet時呼叫的函式
     * @param  {[type]} reason 錯誤資訊 未知
     * @return {[type]}        [description]
     */
    function reject (reason) {
        //如果狀態失敗 更改狀態和賦值
        if (self.status == 'padding') {
            self.reason = reason
            self.status = 'rejected'
            self.rejectedCallBackArr.forEach(callback => callback(self.reason))
        }
    }

    //只要有錯誤 就走tra catch
    try {
        excutor(resolve, reject)
    } catch (e) {
        reject(e)
    }
    // console.log(excutor)
}

/**
 * @desc 在例項上擴充套件then方法
 * @param  {function} onFulfiled 使用者傳入的成功會調函式
 * @param  {function} onRejected 使用者傳入的失敗回撥函式
 * 方法思路:
 * 1.呼叫的時候如果是成功狀態,則呼叫onFulfiled成功狀態函式,並將引數傳入
 * 2.呼叫的時候如果是失敗狀態,則呼叫onRejected成功狀態函式,並將引數傳入
 * 3.呼叫的時候如果是等待狀態,則將傳入的函式快取進入程式池,後期使用者主動觸發的時候呼叫
 * 4.實現功能,返回一個PromiseL的例項
 * @return {undefined}          
 */

PromiseL.prototype.then = function (onFulfiled, onRejected) {
    let self = this
    //用來儲存返回的PromiseL例項
    let promise2 
    //根據狀態呼叫函式
    if (self.status == 'resolved') {
        // onFulfiled(this.value)
        return promise2 = new PromiseL((resolve, reject) => {
            let x = onFulfiled(this.value)
            //判斷 返回的是promise物件或者是值分別處理
            if (x instanceof PromiseL) {
                x.then(resolve, reject)
            } else {
                resolve(x)
            }
        })
    }

    if (self.status == 'rejected') {
        return promise2 = new PromiseL((resolve, reject) => {
            let x = onRejected(self.reason)
            //判斷 返回的是promise物件或者是值分別處理
            if (x instanceof PromiseL) {
                x.then(resolve, reject)
            } else {
                resolve(x)
            }
        })
    }

    //如果是非同步 先將回調函式快取
    if (self.status == 'padding') {
        //如果狀態時padding 分別在程式池儲存reolve和reject的函式 等使用者觸發的時候呼叫
        return promise2 = new PromiseL((resolve, reject) => {
            self.resolvedCallBackArr.push(() => {
                let x = onFulfiled(self.value)
                //判斷 返回的是promise物件或者是值分別處理
                if (x instanceof PromiseL) {
                    x.then(resolve, reject)
                } else {
                    resolve(x)
                }
            })
            self.rejectedCallBackArr.push(() => {
                let x = onRejected(self.reason)
                //判斷 返回的是promise物件或者是值分別處理
                if (x instanceof PromiseL) {
                    x.then(resolve, reject)
                } else {
                    resolve(x)
                }
            })
        })
    }
}

/**
 * @desc 當函式有報錯 最後捕捉錯誤
 * @param  {Function} fn 方法呼叫時的回撥函式
 * @return {object}      return 一個promiseL的例項
 */
PromiseL.prototype.catch = function (fn) {
    // console.log(fn)
    return this.then(null,fn)
}

實現 Promise.all 方法

/**
 * @desc 自定義promiseL類,模擬實現promise物件
 * @param {function} excutor 使用者在初始化Promise物件時傳入的函式
 */
function PromiseL (excutor) {
    let self = this
    self.status = 'padding' //預設等待狀態
    self.value = undefined
    self.reason = undefined
    //因為是非同步呼叫 所以需要把callback快取起來
    self.resolvedCallBackArr = [] //成功的回撥函式
    self.rejectedCallBackArr = [] //失敗的回撥函式

    /**
     * @desc 使用者觸發成功的時候的回到
     * @param  {all} value 使用者傳入的引數 未知型別
     * 
     */
    function resolve (value) {
        //如果函式執行成功,則修改狀態為成功,
        if (self.status == 'padding') {
            self.value = value
            self.status = 'resolved'

            //遍歷呼叫回撥函式
            self.resolvedCallBackArr.forEach(callback => callback(self.value))
        }
    }

    /**
     * @desc 使用者觸發rejcet時呼叫的函式
     * @param  {[type]} reason 錯誤資訊 未知
     * @return {[type]}        [description]
     */
    function reject (reason) {
        //如果狀態失敗 更改狀態和賦值
        if (self.status == 'padding') {
            self.reason = reason
            self.status = 'rejected'
            self.rejectedCallBackArr.forEach(callback => callback(self.reason))
        }
    }

    //只要有錯誤 就走tra catch
    try {
        excutor(resolve, reject)
    } catch (e) {
        reject(e)
    }
    // console.log(excutor)
}

/**
 * @desc 在例項上擴充套件then方法
 * @param  {function} onFulfiled 使用者傳入的成功會調函式
 * @param  {function} onRejected 使用者傳入的失敗回撥函式
 * 方法思路:
 * 1.呼叫的時候如果是成功狀態,則呼叫onFulfiled成功狀態函式,並將引數傳入
 * 2.呼叫的時候如果是失敗狀態,則呼叫onRejected成功狀態函式,並將引數傳入
 * 3.呼叫的時候如果是等待狀態,則將傳入的函式快取進入程式池,後期使用者主動觸發的時候呼叫
 * 4.實現功能,返回一個PromiseL的例項
 * @return {undefined}          
 */

PromiseL.prototype.then = function (onFulfiled, onRejected) {
    //進行引數為空的處理
    onFulfiled = typeof onFulfiled == 'function' ? onFulfiled :  data => data
    onRejected = typeof onRejected == 'function' ? onRejected : err => err
    let self = this
    let promise2
    //根據狀態呼叫函式 resolved 成功態
    if (self.status == 'resolved') {
        // onFulfiled(this.value)
        return promise2 = new PromiseL((resolve, reject) => {
            // 錯誤處理 如果有錯誤 直接進入then的reject狀態
            try {
                let x = onFulfiled(this.value)
                //判斷 返回的是promise物件或者是值分別處理
                if (x instanceof PromiseL) {
                    x.then(resolve, reject)
                } else {
                    resolve(x)
                }
            } catch (e) {
                reject(e)
            }
        })
    }

    //根據狀態呼叫函式 rejected 失敗態
    if (self.status == 'rejected') {
        return promise2 = new PromiseL((resolve, reject) => {
            // 錯誤處理 如果有錯誤 直接進入then的reject狀態
            try {
                let x = onRejected(self.reason)
                //判斷 返回的是promise物件或者是值分別處理
                if (x instanceof PromiseL) {
                    x.then(resolve, reject)
                } else {
                    resolve(x)
                }
            } catch (e) {
                reject(e)
            }
        })
    }

    //如果是非同步 先將回調函式快取
    if (self.status == 'padding') {
        //如果狀態時padding 分別在程式池儲存reolve和reject的函式 等使用者觸發的時候呼叫
        return promise2 = new PromiseL((resolve, reject) => {
            self.resolvedCallBackArr.push(() => {
                let x = onFulfiled(self.value)
                //判斷 返回的是promise物件或者是值分別處理
                if (x instanceof PromiseL) {
                    x.then(resolve, reject)
                } else {
                    resolve(x)
                }
            })
            self.rejectedCallBackArr.push(() => {
                let x = onRejected(self.reason)
                //判斷 返回的是promise物件或者是值分別處理
                if (x instanceof PromiseL) {
                    x.then(resolve, reject)
                } else {
                    resolve(x)
                }
            })
        })
    }
}

/**
 * @desc 當函式有報錯 最後捕捉錯誤
 * @param  {Function} fn 方法呼叫時的回撥函式
 * @return {object}      return 一個promiseL的例項
 */
PromiseL.prototype.catch = function (fn) {
    // console.log(fn)
    return this.then(null,fn)
}

/**
 * @desc 傳入多個promise物件
 * @param  {array} promiseLs 陣列內部為多個Promise例項物件
 * @return {Promise}           返回一個PromiseL物件例項,通過then拿到最後的結果
 */
PromiseL.all = function (promiseLs) {
    return new PromiseL(function (resolve, reject) {
        let result = [] //最終的結果
        let i = 0 //當前完成的數量

        /**
         * @desc 當子promise執行成功的回撥函式
         * @param  {number} index 當前執行的是那一個promise物件
         * @return {[type]}       [description]
         */
        let resolved = function (index) {
            return function (data) {
                result[index] = data
                i++

                if (i == promiseLs.length) {
                    // 所有的promises都執行完畢
                    resolve(result)
                }
            }
        }

        //遍歷所有的物件,呼叫他們的then方法進行處理
        for (let j = 0, len = promiseLs.length; j < len; j++) {
            promiseLs[j].then(resolved(j), err => {
                reject(err)
            })

        } 
    })
}