<!DOCTYPE html>
<html>
<head>
<title>手寫Promise</title>
</head>
<body>
</body>
<script type="text/javascript">
class MyPromise{
constructor(executor){
this.status = "pending";//目前狀态
this.res = null;//傳遞給then的值
this.err = null;//傳遞給錯誤處理的值
this.resolveCallbacks = [];//resolve執行後的回調函數
this.rejectCallbacks = [];//reject執行後的回調函數
try{
executor(this.resolve.bind(this),this.reject.bind(this));//執行器,傳入類中的resolve和reject方法,必須要用bind将this指向new出來的class,否則this指向目前上下文(執行器)就找不到this.resolve。
}catch(error){
this.reject(error);//如果執行器内部出錯,應該直接reject
}
}
resolve(res){
if(this.status !== "pending") return;//根據Promise的規則,已處理的Promise是不能改變狀态的
this.status = "fulfilled";
this.res = res;
setTimeout(() => {//把then變成異步任務
this.resolveCallbacks.map(
(callbackFunction) => {
callbackFunction.onFulfilled(res);
}
);
})
}
reject(err){
if(this.status !== "pending") return;
this.status = "rejected";
this.err = err;
setTimeout(() => {
this.rejectCallbacks.map(
(callbackFunction) => {
callbackFunction.onRejected(err);
});
})
}
then(onFulfilled,onRejected){
//if判斷目前狀态,根據Promise的規則,必須被處理後才能執行then或者catch
if(typeof onFulfilled !== "function"){
onFulfilled = () => this.res;
}
if(typeof onRejected !== "function"){
onRejected = () => this.err;//如果.then中沒有傳入處理錯誤的函數,就要處理一下避免報錯,傳遞this.res和this.err是為了then的穿透傳遞
}
return new MyPromise((resolve,reject) => {//.then傳回的是一個Promise,這樣才能鍊式調用
if(this.status === "pending"){//如果執行到then了還是pending,說明執行器裡的是異步任務,就得将.then裡的函數傳遞到resolve或reject去讓它們異步執行。
this.resolveCallbacks.push({
onFulfilled: res => {
this.parse(onFulfilled(res),resolve,reject);
}
}
);
this.rejectCallbacks.push({
onRejected: err => {
this.parse(onRejected(this.res),resolve,reject);
}
});
}
if (this.status === "fulfilled") {
setTimeout(() => {//用setTimeout把then變成異步任務
this.parse(onFulfilled(this.res),resolve,reject);
})
}
if (this.status === "rejected") {
setTimeout(() => {
this.parse(onRejected(this.res),resolve,reject);
})
}
})
}
parse(result,resolve,reject){//傳入的result是上一個Promise的傳回值
try{
resolve(result);//将then傳回的值傳遞到下一個Promise中以供鍊式調用
}catch(error){
rejected(error);//如果then的處理方法中出錯,傳回的Promise就應該為rejected
}
}
}
let p = new MyPromise((resolve,reject) => {
setTimeout(() => {
resolve("resolve了");
// reject("reject了");
},1000);
}).then(
res => {
return res
}
).then(
res => {
console.log("第二層",res);
}
)
</script>
</html>