JS版本中,更新最大的一個版本就是ES6了,包括了const、let、模板字符串、箭頭函數、類、Generator、Promise等等一系列語法糖。
在ES7沒出來前,Promise是代替傳統回調的主要方式,ES7後更多的是使用async-await,但Pomise的使用仍不在少數
本文章,我們一起實現一個Promise,你可能說,我直接用它就行了,幹嘛自己寫一個。非也,在我看來,理解代碼思想纔是核心,這能大大提高我們的js書寫功底。
下面我們進入正題:
傳參:用then傳入成功或失敗時執行的回調,用catch傳入異常時執行的回調。
返回:都返回promise實例,以實現鏈式調用。
編寫代碼:
class MyPromise
constructor(fn) {
this.doneList = [];
this.failList = [];
this.catchCb = function() {};
setTimeout(() => {
try {
fn(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.catchCb(e);
}
}, 0)
}
// 將 .then裏的第一個參數加入到成功隊列
done(success) {
if(typeof success === "function") {
this.doneList.push(success )
} else {
throw new Error("傳入success的參數必須爲function!");
}
return this;
}
// 將 .then裏的第二個參數加入到失敗隊列
fail(fail) {
if(typeof fail === "function") {
this.failList.push(fail )
} else {
throw new Error("傳入fail的參數爲必須爲function!");
}
return this;
}
// 成功時,遍歷成功隊列,執行裏面的所有函數
resolve(res) {
this.doneList.forEach(fn => {
fn(res);
this.doneList.shift();
})
}
// 成功時,遍歷失敗隊列,執行裏面的所有函數
reject(err) {
this.failList.forEach(fn => {
fn(err);
this.failList.shift();
})
}
// 將 .then裏的第一、二個參數分別加入到成功隊列、失敗隊列
then(success, fail) {
this.done(success || function() {});
this.fail(fail || function() {});
return this;
}
// 程序出現異常時執行的函數
catch(errFn) {
if(typeof errFn !== "function") throw new Error("catch傳入的參數必須爲function");
this.catchCb = errFn;
}
}
代碼解釋:
Promise的核心是“發佈-訂閱”模式,因此需要一個doneList屬性和一個failList屬性,用來存儲所有訂閱者。
catchCb 屬性用來存儲產生異常時執行的回調函數。
done和fail負責將單個訂閱放進doneList或failList。
catch負責放進異常時的回調函數。
then和done、fail一樣,不同在於接受兩個參數,分別放進doneList 和 failList。
resolve實現發佈,此時遍歷doneList,執行其中所有訂閱者。
reject實現發佈,此時遍歷failList,執行其中所有訂閱者。
constructor裏爲什麼要使用setTimeout爲0s?答:目的是將其裏面的代碼放入等待隊列,待所有回調函數全部轉入Promise容器時,才執行等待隊列的代碼。
下面進入測試:
new MyPromise((resolve, reject) => {
setTimeout(() => {
// noExistFn(); // 拋出異常,觸發執行 ①
// resolve("成功了!"); // 觸發執行 ②
reject("失敗了!"); // 觸發執行 ③
}, 1000);
}).then((res) => {
console.log("res >>> ", res) ①
}, (err) => {
console.log("err >> ", err) ②
}).catch((exception) => {
console.log("異常 >> ", exception); ③
});
結果如上,執行noExistFn時,會相應觸發①,以此類推