這部分是讓鏈接都可以在第一層,維持結構扁平。具體來說,在使用 promise 時,如果處理函式回傳一個值,下一個處理函式會得到該值;如果回傳 promise,則下一個處理函式會得到 resolved value,有點像中間已經經過「解開 promise 取值」的效果。例如像下方的 asyncFunc2
回傳 promise,不需要在它後面再呼叫巢狀 then
,而是直接在外層呼叫就可以得到結果:
asyncFunc1()
.then(function (value1) {
return asyncFunc2();
})
.then(function (value2) {
// value2 是 asyncFunc2() promise 的結果
console.log(value2);
});
也可以理解為:如果 promise P
resolve 另一個 promise Q
,P
的狀態和結果只會隨著 Q
改變,它本身不能再被 resolve。而 Q
得到結果後要同步給 P
。
基於以上想法,改寫實作的 resolve
方法。這是之前寫到的部分:
resolve(value) {
if (this.promiseState !== 'pending') return;
this.promiseState = 'fulfilled';
this.promiseResult = value;
this._clearAndEnqueueReactions(this.fulfillReactions);
return this; // 讓後面可以鏈接
}
改成新增一個布林值 alreadyResolved
來鎖住外層 promise 的狀態,只要該值為真,this
就不能再 resolve,實際上狀態結果的改變在 _doResolve
這個方法內進行。而在 _doResolve
中,若回傳的值是 promise (或例子中為 thenable),當有結果時,讓外面鎖定的 promise 也有同樣結果:
resolve(value) {
if (this.alreadyResolved) return;
this.alreadyResolved = true;
this._doResolve(value);
return this;
}
_doResolve(value) {
const self = this;
// 判斷 'value' 是否為 thenable
if (typeof value === 'object' && value !== null && 'then' in value) {
// 把 'value' 的成功或失敗結果同步給 'self'
addToTaskQueue(function () { // (A)
value.then(
function onFulfilled(result) {
self._doResolve(result);
},
function onRejected(error) {
self._doReject(error);
});
});
} else {
this.promiseState = 'fulfilled';
this.promiseResult = value;
this._clearAndEnqueueReactions(this.fulfillReactions);
}
}