從零完成一個淺易的 Promise
一切題目都能夠經由過程加一層中間層來處置懲罰。
淺易的,不做空話直接最先 :)
const p = new Promise((resolve, reject)=>{
// 假如操縱勝利則挪用 resolve 並傳入 value
// 假如操縱失利則挪用 reject 並傳入 reason
});
一般我們都邑運用上述要領獵取 Promise 實例:在組織函數種傳入一個 executor 要領,當同步/異步的使命完成時挪用 resolve,失利時挪用 reject,簡樸易懂,在此不多贅述。
狀況機
一個 Promise 能夠理解為一個狀況機,響應的 API 接口要麼用於轉變狀況機的狀況,要麼在抵達某個狀況時被觸發,因而起首須要完成的是 Promise 的狀況信息:
const PENDING = 0
const FULFILLED = 1
const REJECTED = 2
而且只存在 PENDING => FULFILLED 或許 PENDING => REJECTED 的狀況轉移。
組織函數
起首完成組織函數的框架以下:
class Promise {
constructor(executor) {
this.status = PENDING; // 實例當前的狀況
this.data = undefined; // Promise 返回的值
this.defered = []; // 回調函數集
executor(resolve, reject); // 實行 executor 並傳入響應的參數
}
}
上述代碼基礎完成 Promise 組織函數的主題部份,然則存在三個題目:
- resolve 和 reject 參數/要領還沒有定義
- executor 函數體中能夠會拋出非常,須要做容錯處置懲罰
- 斟酌 executor 函數體中在挪用 resolve/reject 時的 this 指向題目
修修補補以下:
class Promise {
constructor(executor) {
this.status = PENDING;
this.data = undefined;
this.defered = [];
try {
// bind, bind, bind!
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e);
}
}
resolve(value) {
// TODO
}
reject(reason) {
// TODO
}
}
resolve & reject
接下來完成 resolve 和 reject 要領,基礎上就是在推斷狀況為 PENDING 以後把狀況改成響應的值,並把對應的 value 和 reason 存在 self 的 data 屬性上面,末了實行響應的回調函數,邏輯很簡樸:
resolve(value) {
if (this.status === PENDING) {
this.status = FULFILLED;
this.data = value;
this.defered.forEach(i => i.onfulfiled(value));
}
}
reject(reason) {
if (this.status === PENDING) {
this.status = REJECTED;
this.data = reason;
this.defered.forEach(i => i.onrejected(reason));
}
}
then 要領
Promise 對象有一個 then 要領,用來註冊在這個 Promise 狀況肯定后的回調,很明顯 then 要領須要寫在原型鏈上,Promise 總共有三種能夠的狀況,在 then 要領中我們離別用三個推斷分支來處置懲罰,而且都離別返回一個新的 Promise 實例。
then(onResolved, onRejected) {
// 假如 then 的參數不是 function 則我們須要疏忽它
onResolved = typeof onResolved === 'function' ? onResolved : function(v) {};
onRejected = typeof onRejected === 'function' ? onRejected : function(r) {};
switch (this.status) {
case FULFILLED:
return new Promise((resolve, reject) => {
// TODO
});
case REJECTED:
return new Promise((resolve, reject) => {
// TODO
});
case PENDING:
return new Promise((resolve, reject) => {
// TODO
});
}
}
完全的完成以下,个中須要注重的是,假如 onResolved 的返回值是一個 Promise 對象,則直接取它的效果做為新的 Promise 實例的效果:
then(onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : function(v) {};
onRejected = typeof onRejected === 'function' ? onRejected : function(r) {};
switch (this.status) {
case FULFILLED:
return new Promise((resolve, reject) => {
try {
const r = onResolved(this.data);
r instanceof Promise && r.then(resolve, reject);
resolve(r);
} catch (e) {
reject(e);
}
});
case REJECTED:
return new Promise((resolve, reject) => {
try {
const r = onRejected(this.data);
r instanceof Promise && r.then(resolve, reject);
} catch (e) {
reject(e);
}
});
case PENDING:
return new Promise((resolve, reject) => {
const onfulfiled = () => {
try {
const r = onResolved(this.data);
r instanceof Promise && r.then(resolve, reject);
} catch (e) {
reject(e);
}
};
const onrejected = () => {
try {
const r = onRejected(this.data);
r instanceof Promise && r.then(resolve, reject);
} catch (e) {
reject(e);
}
};
this.defered.push({
onfulfiled,
onrejected
});
});
}
}
至此完成一個淺易的 Promise,運用以下測試用例考證:
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
}).then((res) => {
console.log(res);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
}, 1000);
});
}).then((res) => {
console.log(res);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3);
}, 1000);
});
}).then((res) => {
console.log(res);
});
// 1
// 2
// 3
// [Finished in 3.1s]
其他題目(UPDATED)
異步題目
new Promise((resolve) => {
resolve();
})
.then(() => {
console.log('1');
})
.then(() => {
console.log('2');
});
console.log('3');
實行上面的代碼會發明輸出的遞次是“1, 2, 3”,而不是準確的“3, 1, 2”,明顯是因為我們沒有在 Promise 的 resolve 要領中異步的挪用回調函數集致使的,固然處置懲罰這個題目也很簡樸,就是運用 setTimeout,然則如許完成的話並不相符 Promise 在事宜循環中的優先級,所以臨時疏忽。
值穿透題目
new Promise((resolve) => {
resolve(8);
})
.then()
.then()
.then((value) => {
console.log(value)
});
上面的代碼運用我們方才完成的 Promise 會打印 undefined,然而這並非我們希冀獲得的效果,我們願望的是8這個值會穿過兩個 then 抵達鏈尾的 then 的實行函數里,其輸出應當和這段代碼一致:
new Promise((resolve) => {
resolve(8);
})
.then((value) => {
return value;
})
.then((value) => {
return value;
})
.then((value) => {
console.log(value);
});
實在要完成這個功用非常簡樸,只要把 then 的兩個參數的默認值做簡樸的修正:
onResolved = typeof onResolved === 'function' ? onResolved : function(v) { return v; };
onRejected = typeof onRejected === 'function' ? onRejected : function(r) { return r; };