我寫這篇文章不打算介紹Promise產生的原因以及它解決的問題,我只是想寫一篇關於實現自己Promise的文章。如果程式碼以及邏輯有什麼不對的地方,請大家指出來。就這些,開始正題。
前提:我們要知道Promise是基於Promises/A+規範的。其中好多變數和方法名都是從這裡來的。
我們先從Promise的使用開始,寫幾個測試例子。
let promise = new Promise((resolve, reject) =>{
// console.log("1");
// resolve("成功");
// reject("失敗");
// console.log("2");// 第一步
// reject("失敗");
// resolve("成功");// 第二步
// setTimeout(() => {
// resolve("success");
// }, 2000);
throw new Error("手動丟擲錯誤");// 第四步
});
promise.then((value) => {
console.log("then第一個方法:"+value);
}, (err) => {
console.log("then第二個方法:"+err);
})
promise.then((value) => {
console.log("then第一個方法:"+value);
}, (err) => {
console.log("then第二個方法:"+err);
})
console.log("3");
複製程式碼
第一步輸出
- 1
- 2
- 3
- then第一個方法:成功
- then第一個方法:成功
第二步輸出
- 3
- then第二個方法:失敗
- then第二個方法:失敗
第三步輸出
- 3
兩秒之後 - then第一個方法:success
- then第一個方法:success
第四步輸出
- 3
- then第二個方法:Error: 手動丟擲錯誤
- then第二個方法:Error: 手動丟擲錯誤
最後輸出“成功”說明 then是非同步執行的
根據以上幾個例子我們可以推出以下幾點內容:
- Promise是一個建構函式(使用了 new)
- Promise接收一個引數,並且這個引數是一個函式(為了方便描述,我們稱之為 executor)
- executor在 new Promise時執行
- new Promise中可以支援非同步行為(第三步)
- executor有兩個引數(resolve,reject)
- resolve和reject不會我們傳進去的,說明是屬於Promise內容提供的
- resolve和reject都是函式,並且都接收一個引數。看規範:resolve接收引數稱之為value,reject接收引數稱之為reason
- 每個Promise例項上都有then方法
- then方法是非同步的
- then方法中有兩個引數onFulfilled和onRejected 分別是成功的回撥(執行resolve)和失敗的回撥(執行reject)。看這裡
- 一個Promise中resolve和reject只會執行一個,規範中有提到 Promise States,大家可以看下
- 同一個promise的例項可以then多次,成功時回撥用所有的成功方法,失敗時回撥用所有的失敗方法
- 如果發現錯誤就會走入失敗態
這麼一大坨東西,看著有點亂。我們就根據我們得出的結論開始寫屬於自己的Promise。寫的過程中思路慢慢就清晰了。
let myPromise = function (executor) {
let self = this;//快取一下this
self.status = `pending`;// 狀態管理 狀態的變化只能由pending變為resolved或者rejected。一件事情不能既成功又失敗。所以resolved和rejected不能相互轉化。
self.value = undefined;// 成功後的值 傳給resolve
self.reason = undefined;//失敗原因 傳給reject
self.onResolvedCallbacks = [];// 存放then中成功的回撥
self.onRejectedCallbacks = []; // 存放then中失敗的回撥
// 這裡說明一下,第三步使用定時器。執行完 new Promise 之後,會執行then方法,此時會把then中的方法快取起來,並不執行:此時狀態還是pending。等到定時器2秒之後,執行
// resolve|reject 時,而是依次執行存放在陣列中的方法。 參考釋出訂閱模式
function resolve(value) {
// pending => resolved
if (self.status === `pending`) {
self.value = value;
self.status = `resolved`;
// 依次執行快取的成功的回撥
self.onResolvedCallbacks.forEach(fn => fn(self.value));
}
}
function reject(reason) {
// pending => rejected
if (self.status === `pending`) {
self.value = value;
self.status = `rejected`;
// 依次執行快取的失敗的回撥
self.onRejectedCallbacks.forEach(fn => fn(self.reason));
}
}
try {
//new Promise 時 executor執行
executor(resolve, reject);
} catch (error) {
reject(error);// 當executor中執行有異常時,直接執行reject
}
}
// 每個Promise例項上都有then方法
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
// 執行了 resolve
if (self.status === `resolved`) {
// 執行成功的回撥
onFulfilled(self.value);
}
// 執行了 reject
if (self.status === `rejected`) {
// 執行失敗的回撥
onRejected(self.reason);
}
// new Promise中可以支援非同步行為 當既不執行resolve又不執行reject時 狀態是預設的等待態pending
if (self.status === `pending`) {
// 快取成功的回撥
self.onResolvedCallbacks.push(onFulfilled);
// 快取失敗的回撥
self.onRejectedCallbacks.push(onRejected);
}
};
複製程式碼
說明一下:這是最簡版,因為Promise的強大之處是鏈式呼叫。我們這個只是雛形,由於時間關係。我們先到這裡。下一次我們基於這個雛形實現符合Promises/A+規範的完整版。
第一次發表文章,希望各位大蝦多多支援。