Promise
js的單線程特性導(dǎo)致大量的異步操作兢仰,異步操作我們通常使用函數(shù)回調(diào)的方式實(shí)現(xiàn)。大量的函數(shù)回調(diào)會產(chǎn)生我們的毀掉地獄剂碴,降低代碼的可讀性和可維護(hù)性把将。
為了解決這些問題,先后出現(xiàn)了Promise函數(shù)忆矛、Generator函數(shù)和async函數(shù)察蹲。目前Promise配合async/await成為了主流。
Promise本質(zhì)上并沒有改變異步操作催训,只是讓我們可以用同步的代碼寫法去書寫異步操作洽议。增加代碼的可讀性。
Promise是ES6中確定的漫拭,今天我們就使用ES5的寫法亚兄,手動實(shí)現(xiàn)自己的Promise,以求徹底掌握Promise的核心原理采驻。今天我們只封裝實(shí)現(xiàn)Promise的基本功能审胚。
先看一下在ES6中我們是如何使用Promise的
let promiseFn = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 1000)
});
promiseFn.then(res => {
console.log(res) // res === 111
})
// 使用async/await
async function promiseFn () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 1000)
})
}
let res = await promiseFn() // res === 111
Promise規(guī)范
里面詳細(xì)介紹了Promise的各種術(shù)語、定義和規(guī)范挑宠。其中最需要理解的就是Promise的三種狀態(tài)以及其中的狀態(tài)變化⊥怯埃“等待態(tài)(Pending)各淀、執(zhí)行態(tài)(Fulfilled)和拒絕態(tài)(Rejected)”。
狀態(tài)改變不可逆诡挂,只能Pending --> Fulfilled 或者 Pending --> Rejected
預(yù)備
使用status存儲Promise狀態(tài)(pending碎浇、fulfilled临谱、rejected)
使用value存儲resolve的數(shù)據(jù)
使用err存儲reject的錯誤信息
使用原型鏈繼承的方式創(chuàng)建then函數(shù)
使用onFulfilledArr存儲將要執(zhí)行的resolve函數(shù)
使用onRejectedArr存儲將要執(zhí)行的reject函數(shù)
創(chuàng)建 MyPromise構(gòu)造函數(shù)
// 創(chuàng)建 MyPromise構(gòu)造函數(shù)
function MyPromise (fn) {
let self = this;
this.value = null; // 存儲resolve數(shù)據(jù)
this.status = 'pending'; // 存儲狀態(tài)
this.err = null; // 存儲reject錯誤信息
this.onFulfilledArr = []; // 存儲將要執(zhí)行的resolve函數(shù)
this.onRejectedArr = []; // 存儲將要執(zhí)行的reject函數(shù)
function resolveFn (val) { // resolve()時執(zhí)行的函數(shù)
if (self.status === 'pending') { // 只用pending狀態(tài)才能繼續(xù)進(jìn)行
self.value = val; // 存儲數(shù)據(jù)
self.status = 'fulfilled'; // 改變狀態(tài)
// 逐個調(diào)用then()函數(shù)
self.onFulfilledArr.forEach(function(thenFn) {
thenFn(self.value);
});
}
}
function rejectFn(errMsg) { // reject()時執(zhí)行的函數(shù)
if (self.status === 'pending') {
self.err = errMsg;
self.status = 'rejected';
self.onRejectedArr.forEach(function(catchFn) {
catchFn(self.err);
});
}
}
try {
fn(resolveFn, rejectFn);
} catch (e) {
rejectFn(e);
}
}
實(shí)現(xiàn)then()函數(shù)
創(chuàng)建好了Promise構(gòu)造函數(shù)下一步創(chuàng)建then()函數(shù)
MyPromise.prototype.then = function(onFulfilled, onRejected) {
// 如果當(dāng)前處于pending狀態(tài),就將函數(shù)壓入對應(yīng)數(shù)組
var self = this;
if (self.status === 'pending') {
self.onFulfilledArr.push(onFulfilled);
self.onRejectedArr.push(onRejected);
}
// fulfilled狀態(tài)就執(zhí)行onFulfilled()方法
if (self.status === 'fulfilled') {
onFulfilled(self.value);
}
// onFulfilled狀態(tài)就要執(zhí)行onRejected()函數(shù)
if (self.status === 'rejected') {
onRejected(self.err);
}
return this; // return this是鏈?zhǔn)秸{(diào)用關(guān)鍵
};
到此我們就實(shí)現(xiàn)了自己的myPromise()方法奴璃。最關(guān)鍵的還是Promise的三種狀態(tài),理解了三種狀態(tài)的切換就基本掌握了Promise悉默。