一步一步實現一個Promise A+規範的 Promise之二:鏈式調用

鏈式調用

上文有提到標準 Promise 的一些特性,接下來一塊兒來實現 Promise 的鏈式調用。
來看看標準 Promise 的鏈式調用:javascript

var fn = new Promise(function (resolve, reject) {
        setTimeout(function() {
            resolve('oook~')
        }, 500)
    })
    
    fn.then(function(data) {
        console.log('data-1: ', data)
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                reject('不oook~')
            }, 1000)
        })
    }, function(err) {
        console.log('err-1: ', err)
    })
    .then(function(data) {
        console.log('data-2:', data)
    }, function(err) {
        console.log('err-2: ', err)
    })
    .then(function(data) {
        console.log('data-3:', data)
    }, function(err) {
        console.log('err-3: ', err)
    })
複製代碼

能夠看到,通過0.5秒後輸出 data-1: oook~,又通過1秒後輸出 err-2: 不oook~,最後輸出 data-3: undefined

特徵以下:

  • then 方法能夠返回普通值,也能夠返回一個 Promise 對象。
  • 若是 then 方法返回的是一個 Promise 對象,則會根據這個 Promise 對象裏執行的是 resolve 仍是 reject 走後一個 then 方法的成功和失敗回調(本例在第一個 then 裏返回了一個 Promise 對象,並異步調用了 reject ,因此會輸出 err-2: 不oook~)。
  • 若是 then 方法返回的是一個普通值(不管走的成功仍是失敗),那麼這個普通值就會被當作下一個 then 裏成功回調函數的參數(上面例子最後打出 err-3: undefined 就是由於函數默認返回了普通值 undefined)。

根據以上特徵,咱們的 Promise 對象須要增長如下處理:

  1. 只有 Promise 對象纔有 then 方法,因此咱們的 then 方法要支持鏈式調用的話,須要返回一個新的 Promise 對象,並在這個對象裏對要傳遞的值進行處理
  2. 因爲 then 方法的返回值多是一個普通值,也多是一個新的 Promise 對象,Promise 對象裏可能又是一個 Promise 對象,因此咱們須要對這個返回值作一個統一的處理,本例用一個統一的方法 resolvePromise 來處理
代碼以下:
Promise.prototype.then = function (onFulfilled, onRejected) {
        var _this = this
        // 定義一個promise2變量(別問我爲何這麼命名,A+規範裏就是這麼命名的)
        var promise2  
    
        if (_this.status === 'fulfilled') {
             // 返回一個新的promise
            promise2 = new Promise(function (resolve, reject) {
                // A+ 規範規定,onFulfilled 和 onRejected 都須要異步執行,因此加上一個定時器
                setTimeout(function() {
                    try {
                        // x多是個普通值,也多是個promise
                        var x = onFulfilled(_this.successVal)
                        // x也多是第三方的 Promise 庫,用一個函數統一來處理
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })
            });
        }
        if (_this.status === 'rejected') {
             promise2 = new Promise(function (resolve, reject) {
                setTimeout(function() {
                    try {
                        var x = onRejected(_this.failVal)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })
            })
        }
        // 當調用then時,若是是異步操做,就會處於pending狀態
        if (_this.status === 'pending') {
            // 將成功的回調添加到數組中
             promise2 = new Promise(function (resolve, reject) {
                _this.onFulfilledList.push(function () {
                    // 能夠看到,咱們在每個 resolve 和 reject 執行的地方都加上了異步
                    setTimeout(function() {
                        try {
                            var x = onFulfilled(_this.successVal)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })
                })
                
                _this.onRejectedList.push(function () {
                    setTimeout(function() {
                        try {
                            var x = onRejected(_this.failVal)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })
                })
            })
        }
        
        return promise2
    }
    
    function resolvePromise(p2, x, resolve, reject) {
        // 不能返回本身
        if (p2 === x) {   
            return reject(new TypeError('不能循環引用!'))
        }
        // 上一篇有說過,resolve 和 reject 不能同時執行,因此用一個鎖來當開關
        var called     

        // x返回的多是對象和函數也多是一個普通的值
        if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
            try {
            
                var then = x.then
                
                if (typeof then === 'function') {
                    then.call(x, function (y) {
                        // ------- resolve 和 reject 不能同時執行 -------
                        if (called) {
                            return
                        }
                        called = true
                        // 若是成功的話,y有可能也是個 promise,因此遞歸繼續解析
                        resolvePromise(p2, y, resolve, reject)
                        
                    }, function (e) {
                        // ------- resolve 和 reject 不能同時執行 -------
                        if (called) {
                            return
                        }
                        called = true
                        reject(e)
                    })
                    
                } else {    
                    // 若是是普通值,直接返回成功
                    resolve(x)
                }
                
            } catch(e) {
            
                if (called) {
                    return
                }
                
                called = true
                reject(e)
            }
            
        } else {
            resolve(x)
        }
    }

複製代碼

ok,鏈式調用的處理基本上就完成了,下面來看看效果:

var p = new Promise(function(resolve, reject){
        setTimeout(function() {
            resolve('徹底ooooook~')
        }, 500)
    })   
    
    p.then(function (data) {
        console.log('success1: ', data)
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                reject('啊啊啊啊啊啊啊啊啊')
            }, 1000)
        })
    }, function (err) {
        console.log('failed: ', err)
    })
    .then(function (data) {
        console.log('success2: ', data)
    }, function(err) {
        console.log('failed2: ', err)
    })
複製代碼

結果以下: java

結果徹底ooooook啊啊啊啊啊啊數組

上一篇:一步一步來實現一個Promise A+規範的 Promise之二:Promise 鏈式調用promise

相關文章
相關標籤/搜索