本身寫一個Promise

參考Promise 的  官方規範  https://promisesaplus.com/promise

Promise 其實就是一個狀態機異步

它只有兩種狀態變化 pending    =》   fulfilled函數

         pending    =》   rejected測試

而且狀態一旦發生變化後就不會再改變this

咱們用es5來實現下es5

先寫個架子, 並測試下:spa

function myPromise(executor) {
    var _this = this; // 保存當前的函數上下文
    _this.status = 'pending'; // 初始狀態
    _this.resolveValue = null;  // resolve初始值
    _this.rejectValue = null;  // reject初始值
    function resolve(value) {
        if (_this.status ==  'pending') {
            _this.status = 'Fulfilled';
            _this.resolveValue = value;
        }
    }
    function reject(reason) {
        if (_this.status ==  'pending') {
            _this.status = 'Fulfilled';
            _this.rejectValue = reason;
        }
    }
    try {    // 捕獲錯誤
        executor(resolve, reject)
    } catch (e){
        reject(e);
    }
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
    var _this = this;
    if (_this.status == 'Fulfilled') {
        onFulfilled(_this.resolveValue)
    }
    if (_this.status == 'Rejected') {
        onRejected(_this.rejectValue)
    }
};

var p = new myPromise((resolve, reject) => {
    resolve('I am handsome');
    throw Error('捕獲錯誤')
});
p.then((data) => {
    console.log(data)
}, (err) => {
    console.log(err)
} );

結果:prototype

它先執行resolve   狀態 變爲   Fulfilled    ,3d

而後報錯 ,執行reject , 因爲此時狀態不是pending, 狀態仍是Fulfilledcode

Promise的核心是處理異步,

如今咱們的代碼並不能等待狀態的改變,

接下來咱們加上處理異步操做的功能, 並測試下

function myPromise(executor) {
    var _this = this; // 保存當前的函數上下文
    _this.status = 'pending'; // 初始狀態
    _this.resolveValue = null;  // resolve初始值
    _this.rejectValue = null;  // reject初始值
    _this.resolveCallbackList = []; // 存resolve的回調
    _this.rejectCallbackList = []; // 存reject的回調
    function resolve(value) {
        if (_this.status ==  'pending') {
            _this.status = 'Fulfilled';
            _this.resolveValue = value;
            // 狀態改變執行存的回調
            _this.resolveCallbackList.forEach(function(ele){
                if (ele) {
                    ele();
                }
            })
        }
    }
    function reject(reason) {
        if (_this.status ==  'pending') {
            _this.status = 'Rejected';
            _this.rejectValue = reason;
            // 狀態改變執行存的回調
            _this.rejectCallbackList.forEach(function(ele){
                if (ele) {
                    ele();
                }
            })
        }
    }
    try {    // 捕獲錯誤
        executor(resolve, reject)
    } catch (e){
        reject(e);
    }
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
    var _this = this;
    if (_this.status == 'Fulfilled') {
        onFulfilled(_this.resolveValue)
    }
    if (_this.status == 'Rejected') {
        onRejected(_this.rejectValue)
    }
    // 等待狀態時把回調存起來,狀態改變再觸發
    if (_this.status == 'pending') {
        _this.resolveCallbackList.push(function () {
            onFulfilled(_this.resolveValue)
        });
        _this.rejectCallbackList.push(function () {
            onRejected(_this.rejectValue)
        });
    }
};

var p = new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('I am handsome');
    }, 0);
    // throw Error('捕獲錯誤')
});
p.then((data) => {
    console.log(data)
}, (err) => {
    console.log(err)
} );

結果:

 

 🆗  它已經能處理異步操做了

 

接下來實現鏈式操做, 再測試下

function myPromise(executor) {
    var _this = this; // 保存當前的函數上下文
    _this.status = 'pending'; // 初始狀態
    _this.resolveValue = null;  // resolve初始值
    _this.rejectValue = null;  // reject初始值
    _this.resolveCallbackList = []; // 存resolve的回調
    _this.rejectCallbackList = []; // 存reject的回調
    function resolve(value) {
        if (_this.status ==  'pending') {
            _this.status = 'Fulfilled';
            _this.resolveValue = value;
            // 狀態改變執行存的回調
            _this.resolveCallbackList.forEach(function(ele){
                if (ele) {
                    ele();
                }
            })
        }
    }
    function reject(reason) {
        if (_this.status ==  'pending') {
            _this.status = 'Rejected';
            _this.rejectValue = reason;
            // 狀態改變執行存的回調
            _this.rejectCallbackList.forEach(function(ele){
                if (ele) {
                    ele();
                }
            })
        }
    }
    try {    // 捕獲錯誤
        executor(resolve, reject)
    } catch (e){
        reject(e);
    }
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
    var _this = this;
    // 用於鏈式調用
    var nextPromise = new myPromise(function(res, rej) {
        if (_this.status == 'Fulfilled') {
            // 存一下回調執行的結果,傳給下一個.then
            var nextResolveValue = onFulfilled(_this.resolveValue);
            res(nextResolveValue);
        }
        if (_this.status == 'Rejected') {
            // 存一下回調執行的結果,傳給下一個.then
            var nextRejectValue = onRejected(_this.rejectValue);
            rej(nextRejectValue);
        }
        // 等待狀態時把回調存起來,狀態改變再觸發
        if (_this.status == 'pending') {
            _this.resolveCallbackList.push(function () {
                // 存一下回調執行的結果,傳給下一個.then
                var nextResolveValue = onFulfilled(_this.resolveValue);
                res(nextResolveValue);
            });
            _this.rejectCallbackList.push(function () {
                var nextRejectValue = onRejected(_this.rejectValue);
                rej(nextRejectValue);
            });
        }
    });
    return nextPromise
};

var p = new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('I am handsome');
    }, 0);
    // throw Error('捕獲錯誤')
});
p.then((data) => {
    console.log(data + ' suc' + ' 1')
    return 222
}, (err) => {
    console.log(err)
} ).then((data) => {
    console.log(data + ' suc' + ' 2')
}, (err) => {
    console.log(err)
} );

結果 :

沒毛病, 能夠鏈式調用then了  , 先不處理返回值爲Promise  的 狀況  ,

原生的Promise 執行方法都是異步的  , 而且執行方法是能捕捉錯誤,

咱們加上這個功能 , 而且測試下

function myPromise(executor) {
    var _this = this; // 保存當前的函數上下文
    _this.status = 'pending'; // 初始狀態
    _this.resolveValue = null;  // resolve初始值
    _this.rejectValue = null;  // reject初始值
    _this.resolveCallbackList = []; // 存resolve的回調
    _this.rejectCallbackList = []; // 存reject的回調
    function resolve(value) {
        if (_this.status ==  'pending') {
            _this.status = 'Fulfilled';
            _this.resolveValue = value;
            // 狀態改變執行存的回調
            _this.resolveCallbackList.forEach(function(ele){
                if (ele) {
                    ele();
                }
            })
        }
    }
    function reject(reason) {
        if (_this.status ==  'pending') {
            _this.status = 'Rejected';
            _this.rejectValue = reason;
            // 狀態改變執行存的回調
            _this.rejectCallbackList.forEach(function(ele){
                if (ele) {
                    ele();
                }
            })
        }
    }
    try {    // 捕獲錯誤
        executor(resolve, reject)
    } catch (e){
        reject(e);
    }
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
    var _this = this;
    // 用於鏈式調用
    var nextPromise = new myPromise(function(res, rej) {
        if (_this.status == 'Fulfilled') {
            // 存一下回調執行的結果,傳給下一個.then
            setTimeout(function () {
                // 捕獲錯誤
                try {
                    var nextResolveValue = onFulfilled(_this.resolveValue);
                    res(nextResolveValue);
                } catch (e) {
                    rej(e)
                }

            },0)
        }
        if (_this.status == 'Rejected') {
            // 存一下回調執行的結果,傳給下一個.then
            setTimeout(function () {
                // 捕獲錯誤
                try {
                    var nextRejectValue = onRejected(_this.rejectValue);
                    rej(nextRejectValue);
                } catch (e) {
                    rej(e)
                }
            },0)
        }
        // 等待狀態時把回調存起來,狀態改變再觸發
        if (_this.status == 'pending') {
            _this.resolveCallbackList.push(function () {
                // 存一下回調執行的結果,傳給下一個.then
                setTimeout(function () {
                    // 捕獲錯誤
                    try {
                        var nextResolveValue = onFulfilled(_this.resolveValue);
                        res(nextResolveValue);
                    } catch (e) {
                        rej(e)
                    }
                },0)
            });
            _this.rejectCallbackList.push(function () {
                setTimeout(function () {
                    // 捕獲錯誤
                    try {
                        var nextRejectValue = onRejected(_this.rejectValue);
                        rej(nextRejectValue);
                    } catch (e) {
                        rej(e)
                    }
                },0)
            });
        }
    });
    return nextPromise
};

var p = new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('I am handsome');
        console.log(111)
    }, 0);
    // throw Error('捕獲錯誤')
});
p.then((data) => {
    console.log(data + ' suc' + ' 1');
    throw Error('bao cuo')
}, (err) => {
    console.log(err + ' err' + ' 1')
} ).then((data) => {
    console.log(data + ' suc' + ' 2')
}, (err) => {
    console.log(err + ' err' + ' 2')
} );
console.log(222);

預期結果  222  =》 111 =》 I am handsome suc 1    =》   Error: bao cuo err 2

實際結果:

 

 沒毛病, 異步而且捕獲到錯誤了

咱們再來處理 空 then()    就是then裏面不傳參數的狀況, 並測試

myPromise.prototype.then = function (onFulfilled, onRejected) {
    // 參數爲空把值直接傳給下一個then
    if (!onFulfilled) {
        onFulfilled = function (val) {
            return val;
        }
    }
    if (!onRejected) {
        onRejected = function (val) {
            return new Error(val)
        }
    }
    var _this = this;
    // 用於鏈式調用
    var nextPromise = new myPromise(function(res, rej) {
        if (_this.status == 'Fulfilled') {
            // 存一下回調執行的結果,傳給下一個.then
            setTimeout(function () {
                // 捕獲錯誤
                try {
                    var nextResolveValue = onFulfilled(_this.resolveValue);
                    res(nextResolveValue);
                } catch (e) {
                    rej(e)
                }

            },0)
        }
        if (_this.status == 'Rejected') {
            // 存一下回調執行的結果,傳給下一個.then
            setTimeout(function () {
                // 捕獲錯誤
                try {
                    var nextRejectValue = onRejected(_this.rejectValue);
                    rej(nextRejectValue);
                } catch (e) {
                    rej(e)
                }
            },0)
        }
        // 等待狀態時把回調存起來,狀態改變再觸發
        if (_this.status == 'pending') {
            _this.resolveCallbackList.push(function () {
                // 存一下回調執行的結果,傳給下一個.then
                setTimeout(function () {
                    // 捕獲錯誤
                    try {
                        var nextResolveValue = onFulfilled(_this.resolveValue);
                        res(nextResolveValue);
                    } catch (e) {
                        rej(e)
                    }
                },0)
            });
            _this.rejectCallbackList.push(function () {
                setTimeout(function () {
                    // 捕獲錯誤
                    try {
                        var nextRejectValue = onRejected(_this.rejectValue);
                        rej(nextRejectValue);
                    } catch (e) {
                        rej(e)
                    }
                },0)
            });
        }
    });
    return nextPromise
};

var p = new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('I am handsome');
    }, 0);
    // throw Error('捕獲錯誤')
});
p.then((data) => {
    console.log(data + ' suc' + ' 1');
    throw Error('bao cuo')
}, (err) => {
    console.log(err + ' err' + ' 1')
} ).then( ).then((data) => {
    console.log(data + ' suc' + ' 3')
}, (err) => {
    console.log(err + ' err' + ' 3')
} );

結果:

 

🆗  第一個then裏拋出的錯誤被第三個then 接受到了, 沒毛病

接下來處理 返回值爲promise的狀況, 並測試

若是返回值爲promise,後面的then就取決於返回的promise的狀態

// 處理返回值的函數
function ResolutionRetrunPromise (nextPromise, returnValue, res, rej) {
    // 返回值是不是promise
    if (returnValue instanceof  myPromise) {
        returnValue.then(function (val) {
            res(val)
        },function (reason) {
            rej(reason)
        })
    } else {
        res(returnValue)
    }
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
    // 參數爲空把值直接傳給下一個then
    if (!onFulfilled) {
        onFulfilled = function (val) {
            return val;
        }
    }
    if (!onRejected) {
        onRejected = function (reason) {
            return new Error(reason)
        }
    }
    var _this = this;
    // 用於鏈式調用
    var nextPromise = new myPromise(function(res, rej) {
        if (_this.status == 'Fulfilled') {
            // 存一下回調執行的結果,傳給下一個.then
            setTimeout(function () {
                // 捕獲錯誤
                try {
                    var nextResolveValue = onFulfilled(_this.resolveValue);
                    // 處理返回值
                    ResolutionRetrunPromise(nextPromise, nextResolveValue, res, rej)
                    // res(nextResolveValue);
                } catch (e) {
                    rej(e)
                }

            },0)
        }
        if (_this.status == 'Rejected') {
            // 存一下回調執行的結果,傳給下一個.then
            setTimeout(function () {
                // 捕獲錯誤
                try {
                    var nextRejectValue = onRejected(_this.rejectValue);
                    ResolutionRetrunPromise(nextPromise, nextRejectValue, res, rej)
                    // rej(nextRejectValue);
                } catch (e) {
                    rej(e)
                }
            },0)
        }
        // 等待狀態時把回調存起來,狀態改變再觸發
        if (_this.status == 'pending') {
            _this.resolveCallbackList.push(function () {
                // 存一下回調執行的結果,傳給下一個.then
                setTimeout(function () {
                    // 捕獲錯誤
                    try {
                        var nextResolveValue = onFulfilled(_this.resolveValue);
                        ResolutionRetrunPromise(nextPromise, nextResolveValue, res, rej)
                        // res(nextResolveValue);
                    } catch (e) {
                        rej(e)
                    }
                },0)
            });
            _this.rejectCallbackList.push(function () {
                setTimeout(function () {
                    // 捕獲錯誤
                    try {
                        var nextRejectValue = onRejected(_this.rejectValue);
                        ResolutionRetrunPromise(nextPromise, nextRejectValue, res, rej)
                        // rej(nextRejectValue);
                    } catch (e) {
                        rej(e)
                    }
                },0)
            });
        }
    });
    return nextPromise
};

var p = new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('I am handsome');
    }, 1000);
});
p.then((data) => {
    console.log(data + ' suc' + ' 1');
    return new myPromise((resolve, reject) => {
        reject('promise')
    })
}, (err) => {
    console.log(err + ' err' + ' 1')
} ).then((data) => {
    console.log(data + ' suc' + ' 3')
}, (err) => {
    console.log(err + ' err' + ' 3')
} );

 

 結果:

到此 Promise 的 基本功能就實現了  , 

感興趣的同窗能夠基於此 本身實現一下Promise 的   靜態方法 。 。 。 。。 。 

相關文章
相關標籤/搜索