學習Promise

一、Promise

1.異步任務的處理

在ES6出來之后,有很多關于Promise的講解、文章,也有很多經典的書籍講解Promise.

  • 雖然等你學會了Promise之后,會覺得Promise不過如此,但是在初次接觸的時候都會覺得這個東西不好理解。

那么這里我從幾個實際的例子來作為切入點:

  • 我們調用一個函數,這個函數中發送網絡請求(我們可以用定時器來模擬)
  • 如果發送網絡請求成功了,那么告知調用者發送成功,并且將相關數據返回過去。
  • 如果發送網絡請求失敗了,那么告知調用者發送失敗,并且告知錯誤信息。

【任何一個新技術的出來,就是用來解決原有技術的某一個痛點】

//request.js
function requestData(url){
  // 模擬網絡請求
  setTimeout(()=>{
    //拿到請求的1結果
    //url傳入的是 coderwhy,請求成功
    if(url==="coderwhy"){
        let names=["wjy","hyz","tqy"];

        return names;//* 但其實這個return外面是拿不到結果的
    }else{// 否則請求失敗
      let errMessage="請求失敗,url錯誤";

      return errMessage;//* 但其實這個return外面是拿不到結果的
    }
    
  },3000)
}

// main.js
requestData("coderwhy")

修改requestData參數,需要傳入成功的回調函數successCallback和失敗的回調函數failCallback。

//request.js
function requestData(url,successCallback,failCallback){
  // 模擬網絡請求
  setTimeout(()=>{
    //拿到請求的1結果
    //url傳入的是 coderwhy,請求成功
    if(url==="coderwhy"){
        let names=["wjy","hyz","tqy"];
        successCallback(names);
    }else{// 否則請求失敗
      let errMessage="請求失敗,url錯誤";
      failCallback(errMessage)
    }
    
  },3000)
}

// main.js
requestData("coderwhy",(res)=>{
  console.log("成功:",res);
},(err)=>{
  console.log("失敗:",err);
})

1.1 回調函數的弊端

  • 如果是我們自己封裝的requestData,那么我們在封裝的時候必須要自己設計好callback名稱,并且使用好
  • 如果我們使用的是別人封裝的requestData或者一些第三方庫,那么我們必須去看別人的源碼或者文檔,才知道這個函數怎么去獲取結果的。
  • 這種溝通成本非常多的

那么有沒有一種更好的方式:

  • 那么有沒有會返回一個承諾,這個承諾(規范了所有的代碼編寫邏輯)
// *  更好的方案 承諾(規范好了所有的代碼編寫邏輯)
function requestData2(){
  return "承諾"
}

const chengnuo=requestData2()

2.什么是Promise

Promise是ES6新增的一個API,它是一個類,可以翻譯成 承諾、許諾、期約;

當我們需要給予調用者一個承諾:待會兒我會傳給你回調數據時,就可以創建一個Promise對象

在通過new 創建Promise對象時,我們需要傳入一個回調函數,我們稱之為executor

  • 這個回調函數會被立即執行,并且給傳入另外兩個回調函數resolve、reject
  • 當我們調用resolve回調函數時,會執行Promise對象的then方法傳入的回調函數
  • 當我們調用reject回調函數時,會執行Promise對象的catch方法傳入的回調函數。
image-20220514142507394.png
function foo(){
  // Promise
  return new Promise((resolve,reject)=>{
    // resolve();
    reject();
  })
}

// main.js
const fooPromise=foo();

// * then方法傳入的回調函數,會在Promise執行resolve函數時,會回調。
fooPromise.then(()=>{

})

// * catch方法傳入的回調函數,會在Promise執行reject函數時,被回調
fooPromise.catch(()=>{

})

// class Person{
//   constructor(callback){
//     function foo(){

//     }
//     function bar(){

//     }
//     callback(foo,bar)
//   }
// }

// const p=new Person((foo,bar)=>{
//   foo();
//   bar()
// });

// * Promise是一個類,可以傳入參數,參數是回調函數,這個回調函數在傳入時,會立即被執行。
/**
 * * 傳入的回調函數可以稱之為 executor
 * * 這個回調函數會有兩個參數:
 * * resolve :成功時,執行resolve回調
 * * reject:失敗時,執行reject回調
 */
const promise=new Promise((resolve,reject)=>{
  // console.log("promise傳入的函數立即被執行了");
  resolve();
})

promise.then(()=>{

})

promise.catch(()=>{
  
})
image-20220514144055335.png

2.1 異步處理的Promise方式

/**
 * * 回調的弊端
 * *   1.如果是我們自己封裝的requestData,那么我們在封裝的時候必須要自己設計好callback名稱,并且使用好
* *    2.如果我們使用的是別人封裝的requestData或者一些第三方庫,那么我們必須去看別人的源碼或者文檔,才知道這個函數怎么去獲取結果的。
* *    3.這種溝通成本非常多的
 */

//request.js
function requestData(url,successCallback,failCallback){
  // 模擬網絡請求
  
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      //拿到請求的1結果
      //url傳入的是 coderwhy,請求成功
      if(url==="coderwhy"){
          let names=["wjy","hyz","tqy"];
          resolve(names);
      }else{// 否則請求失敗
        let errMessage="請求失敗,url錯誤";
        reject(errMessage)
      }
      
    },3000);
  })
}



//main.js

const promise=requestData("coderwhy");

// * then方法傳入兩個回調函數
// * 第一個回調函數,會在Promise執行resolve函數時,被回調
// * 第二個回調函數,會在Promise執行reject函數時,被回調
promise.then((res)=>{
  console.log("請求成功:",res);
},(err)=>{
  console.log("請求失敗了:",err);
})

3.Promise的三種狀態

// 完全等價于下面的代碼
new Promise((resolve,reject)=>{
  console.log("------------------");//* 階段:pending 
  resolve();
}).then(res=>{
  console.log("res:",res);//* fulfilled(固定、已敲定)
},err=>{
  console.log("err:",err);//* rejected (已拒絕 )
})

上面的Promise使用過程,我們可以將它劃分成三個狀態:

  • 待定(pending):初始狀態,既沒有被兌現,也沒有被拒絕

    • 當執行executor中的代碼時,處于該狀態。
  • 已兌現(fulfilled):意味著操作成功完成

    • 執行了resolved時,處于該狀態
  • 已拒絕(rejected):意味著操作失敗

    • 執行了reject 時,處于該狀態

Promise狀態一旦被確定下來,那么就是不可更改的(鎖定),例如下面我們先執行了resolve,將狀態改為 已兌現(fulfilled)。后面又執行了reject,企圖將狀態修改為已拒絕(rejected),但發現其實并不能進行修改的。

// * Promise狀態一旦被確定下來,那么就是不可更改的(鎖定)
new Promise((resolve,reject)=>{
  console.log("------------------");//* 階段:pending 
  resolve();//* fulfilled(固定、已敲定)
  reject();////* rejected (已拒絕 ) ,這行代碼沒有任何意義。
  // resolve(123)
}).then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err:",err);
})

4. resolve參數

  • 情況一:如果resolve傳入一個普通的值或者對象,那么這個值就會作為then回調的參數
  • 情況二:如果resolve傳入的是另外一個Promise,那么這個新Promise的狀態會決定原Promise的狀態
  • 情況三:如果resolve傳入的是一個對象,并且這個對象有實現then方法,那么就會執行then方法,并且根據then方法的結果來決定Promise的狀態。
/**
 * resolve(參數)
 * *  (1)普通的值或者對象
 * *  (2)傳入一個Promise
 * *    那么當前的Promise狀態由傳入的Promise來決定
 * *    相當于狀態進行了移交
 * *  (3)傳入一個對象,并且這個對象有實現的then方法 (thenable),那么也會執行該then方法,并且由該then方法決定后續狀態
 */

// * 傳入Promise的特殊情況
// const newPromise=new Promise((resolve,reject)=>{
//   // resolve("aaaaa")
//   reject("err message")
// })
// new Promise((resolve,reject)=>{
//   resolve(newPromise)
// }).then(res=>{
//   console.log("res:",res);
// },err=>{
//   console.log("err:",err);
// })



//*  2.傳入一個對象,這個對象有實現then方法,由該then方法決定后續狀態
new Promise((resolve,reject)=>{

  const obj={
    then:function(resolve,reject){
      // resolve("resolve message");

      reject("reject message")
    }
  }
  resolve(obj);
}).then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err:",err);
}) 

5.then方法

5.1 then方法-接受兩個參數

then方法是Promise對象的一個方法,它其實是 放在Promise的原型上的Promise.prototype.then

then方法接受兩個參數:

  • fulfilled的回調函數:當狀態變成fulfilled時會回調的函數
  • rejected的回調函數:當狀態變成rejected時會回調的函數
promise.then(res=>{
  console.log("res:",res);
},err=>{
 console.log("err:",err); 
})

// 等價于下面
promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})

5.2 then方法-可以多次調用

同一個promise對象的then方法可以調用多次。

當resolve方法被回調時,所有傳入到then方法的回調函數會執行。

// * Promise有哪些對象方法
// console.log(Promise.prototype);
// console.log(Object.getOwnPropertyDescriptors(Promise.prototype));

const promise=new Promise((resolve,reject)=>{
  resolve("hahahaha")
})

// *同一個promise可以多次調用then方法
// * 當我們的resolve方法被回調時,所有的then方法傳入的回調函數都會被調用
promise.then((res)=>{
  console.log("res:",res);
})


promise.then((res)=>{
  console.log("res2:",res);
})

promise.then((res)=>{
  console.log("res3:",res);
})

5.3 then方法——返回值

其實then方法有返回值,返回的是新的Promise對象

then方法的回調函數也有返回值,當then方法中的回調函數返回一個結果時,那么它處于fulfilled狀態,并且會將結果作為resolve的參數

  • 如果返回的是一個普通的值(數字、字符串、對象),這個值會作為then方法返回的Promise對象的resolve的值

    • 如果沒有返回值,則默認返回的是undefined

      const promise=new Promise((resolve,reject)=>{
        resolve("hahahaha")
      })
      promise.then(res=>{
        // *如果回調函數沒有返回值,則返回的是一個undefined
        return {name:"wjy"}
      }).then(res=>{
        console.log("res:",res);
      })
      
      
  • 如果返回的是一個Promise對象,

    • 這個返回的Promise對象會決定then方法返回的Promise的狀態
    const promise=new Promise((resolve,reject)=>{
      resolve("hahahaha")
    })
    // *如果返回的是一個Promise對象
    promise.then(res=>{
      return new Promise((resolve,reject)=>{
        setTimeout(()=>{
          resolve("hello wjy")
        },3000)
      })
    }).then(res=>{
      console.log("res:",res);
    })
    
    
  • 如果返回的是一個對象,這個對象實現了thenable(then方法),會立即執行then方法,并根據then方法的結果來決定Promise的狀態。
// *如果返回了是一個對象,并且這個對象上
promise.then(res=>{  
  return {  //* new Promise(resolve=>resolve(obj.then))
    then:function(resolve,reject){
      resolve(2222)
    }
  } 
}).then(res=>{
  console.log("res:",res);
})

6.catch方法

then方法內部可以傳入兩個參數(兩個回調函數)

  • 當resolve函數被執行時,會調用then方法的第一個參數(回調函數)

  • 當reject函數被執行時,會調用then方法的第二個參數(回調函數)【或者內部發生錯誤,也會被then方法的第二個參數捕獲到。】

    • const promise=new Promise((resolve,reject)=>{
        reject("rejected status")
      })
      
      promise.then(undefined,err=>{
        console.log("err:",err);
      })
      
    • const promise=new Promise((resolve,reject)=>{
        throw new Error("rejected status")
      })
      
      promise.then(undefined,err=>{
        console.log("err:",err);
      })
      

如果將成功和失敗的回調函數寫在一塊,閱讀性差,比如下面:

const promise=new Promise((resolve,reject)=>{
  // reject("rejected status")
  throw new Error("rejected status")
})

promise.then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err:",err);
})

支持另外一種方法:

通過catch方法傳入錯誤或拒絕的捕獲的回調函數:

const promise=new Promise((resolve,reject)=>{
  reject("rejected status")
})


// * 通過catch方法傳入錯誤或(拒絕)捕獲的回調函數
// promise/a+規范
promise.catch(err=>{
  console.log("err:",err)
})

還支持另外一種寫法:

  • catch會優先捕獲第一個Promise對象的異常捕獲,如果第一個Promise對象沒有發生異常,則不會使用,會留著下一次使用。如果第二個Promise對象發生異常,這個catch會去捕獲。
  • 這個catch方法比較特殊
const promise=new Promise((resolve,reject)=>{
  reject("rejected status")
  // throw new Error("rejected status")
})


promise.then(res=>{
  return 111
}).catch(err=>{
     console.log("err:",err)
})

image-20220514193022157.png
const promise=new Promise((resolve,reject)=>{
  resolve("resolve status")
})


promise.then(res=>{
  throw new Error("發生錯誤")
  return 111
}).catch(err=>{
  console.log("err:",err);//*如果第一個promise對象沒有異常,所以就不會執行,等著下一次使用,會給下一個Promise對象使用
  console.log("------");
})
image-20220514193638998.png

6.1 拒絕捕獲的問題

// * 拒絕捕獲的問題(前面課程)
const promise=new Promise((resolve,reject)=>{
  reject("rejected status");//* 有點類似拋出異常
})
promise.then(res=>{
  console.log("res:",res);
})

promise.catch(err=>{
  console.log("err:",err);
})

這個代碼運行后會報錯的。

image-20220514195146223.png
  • 之間不會相互影響的
  • 因為在then方法中沒有進行捕獲,以異常的方式退出。
  • 如果代碼中沒有then方法就不會報錯

改成下面這種就不會報錯:

// * 拒絕捕獲的問題(前面課程)
const promise=new Promise((resolve,reject)=>{
  reject("rejected status");//* 有點類似拋出異常
})
promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})

const promise=new Promise((resolve,reject)=>{
  reject("rejected status");//* 有點類似拋出異常
})
promise.then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err:",err);
})

6.2 reject和throw同時存在拋出哪個異常

如果執行了reject(),throw會被忽略

如果執行了throw,throw后面的代碼都不會再執行。

6.3 catch方法多次調用

catch方法也是Promise對象上的一個方法,它也是放在Promise的原型上的Promise.prototype.catch方法。

同一個Promise對象的catch方法可以被調用多次

  • 每當調用我們可以傳入對應的reject回調
  • 當Promise的狀態變成rejected的時候,這些回調函數都會被執行。
const promise=new Promise((resolve,reject)=>{
  reject("aaa");
})

promise.catch(err=>{
  console.log("err1:",err);
})

promise.catch(err=>{
  console.log("err2:",err);
})

promise.catch(err=>{
  console.log("err3:",err);
})

6.4 catch方法——返回值

事實上catch方法也是會返回一個Promise對象的,所以catch方法后面我們可以繼續調用then方法或者catch方法

 const promise=new Promise((resolve,reject)=>{
  reject("aaa");
})

promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
  return "catch return value"
}).then(res=>{
  console.log("res:",res);
})
const promise=new Promise((resolve,reject)=>{
  reject("aaa");
})
promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve("my name")
    },3000)
  })
}).then(res=>{
  console.log("res:",res);
})

7.fanally方法

fanally是ES9(ES2018)新增的一個特性:表示無論Promise的狀態變為fulfilled還是reject狀態,最終都會被執行的代碼。

finally方法是不接收參數的,因為無論前面是fulfilled狀態,還是reject狀態,它都會執行。

const promise=new Promise((resolve,reject)=>{
  resolve("resolve message");
})

promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
}).finally(()=>{
  console.log("finally code execute");
})

finally其實也是返回一個Promise對象,但是其實很少人會用它

8.類方法——resolve方法

前面我們學習的then、catch、finally方法都屬于Promise的實例方法,都是存放在Promise的prototype上的。

下面我們將學習類方法

有時候我們已經有一個現成的內容,希望將其轉成Promise來使用,這個時候我們可以使用Promise.resolve方法來完成。

  • Promise.resolve()方法:相當于new Promise,并且執行resolve操作。

resolve的參數形式:

  • 情況一:參數是一個普通的值或者對象
  • 情況二:參數是一個Promise對象
  • 情況三:參數是一個thenable
function foo(){
  const obj={name:"wjy"}
  return new Promise((resolve)=>{
    resolve(obj);
  });
}

foo().then(res=>{
  console.log("res:",res);
})

等價于下面:

function foo(){
  const obj={name:"wjy"}
 return Promise.resolve(obj);
}

foo().then(res=>{
  console.log("res:",res);
})

8.1 參數形式

// * 1.傳入普通的值
// const promise=Promise.resolve({name:"wjy"});

// * 2.傳入一個Promise,由這個新的Promise對象決定原Promise對象的狀態
// const promise=Promise.resolve(new Promise((resolve,reject)=>{
//   // resolve("resolve2 message")
//     reject("reject message")
// }))

// promise.then(res=>{
//   console.log("res:",res);
// }).catch(err=>{
//   console.log("err:",err);
// })

// * 3. 傳入thenable對象(實現了then方法),會立即執行then方法,由then方法的結果決定其Promise的狀態
const promise=Promise.resolve({
  then:function(resolve,reject){
    // resolve("resolve ");
    reject("reject message")
  }
})

promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})

9.類方法——reject方法

reject方法類似于resolve方法,只是會將Promise對象的狀態設置為rejected狀態

Promise.reject的用法相當于new Promise,并且會調用reject

Promise.reject無論傳過來的參數是什么狀態,都會直接作為reject的參數傳遞到catch的。

10.類方法——all方法

它的作用是將多個Promise包裹在一起,形成一個新的Promise

新的Promise狀態由包裹的所有Promise決定

  • 當所有的Promise狀態變為fulfilled狀態時,新的Promise狀態為fulfilled,并且會將所有的Promise的返回值組成一個數組
  • 當有一個Promise狀態變為rejected狀態時,新的Promise狀態為rejected,并且會將第一個reject的返回值作為參數
const p1=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(1111)
  },1000)
})
const p2=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(22222)
  },2000)
})
const p3=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(33333)
  },3000)
})

// * 需求:所有的Promise都變成fulfilled,再拿到結果
//*  意外:在拿到所有結果之前,有一個promise變成了rejected,那么整個promise是rejected
Promise.all([p1,p2,p3,"aaaa"]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  // * 最后轉到catch執行
  console.log("err:",err);
})

// * all:所有的promise為fulfilled時才會執行then方法,如果有一個狀態為rejected,就會轉成執行catch方法

11.類方法——allSettled方法

all方法有一個缺陷:當有一個Promise變成rejected狀態時,新Promise就會立即變成對應的rejected狀態。

  • 那么對于resolved的,以及仍然處于pending狀態的Promise,我們是獲取不到對應的結果的。

在ES11(ES2020)中,添加了新的API Promise.allSettled

  • 該方法會在所有的Promise都有結果(settled),無論是fulfilled,還是rejected時,才會有最終的狀態。
  • 并且這個Promise的結果一定是fulfilled的
const p1=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(1111)
  },1000)
})
const p2=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(22222)
  },2000)
})
const p3=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(33333)
  },3000)
})


// allSettled
// * 新的Promise的狀態一定是fulfilled
Promise.allSettled([p1,p2,p3]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})

12. 類方法——race

如果有一個Promise有了結果,我們就希望決定最終新的Promise的狀態,那么可以使用race方法

  • race是競技、競賽的意思,表示多個Promise相互競爭,誰先有結果,那么就使用誰的結果。
const p1=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(1111)
  },1000)
})
const p2=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    resolve(22222)
  },2000)
})
const p3=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(33333)
  },3000)
})


// * race :競技 競賽
Promise.race([p1,p2,p3]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})

13.類方法——any方法

any方法是ES12中新增的方法,和race方法是類似的:

  • any方法會等到一個fulfilled狀態,才會決定新Promise的狀態
  • 如果所有的Promise都是rejected的,那么也會等到所有的Promise都變成rejected狀態。
const p1=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(1111)
  },1000)
})
const p2=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(22222)
  },2000)
})
const p3=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(33333)
  },3000)
})


// * any
Promise.any([p1,p2,p3]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  // *可以通過.errors拿到合計的錯誤信息
  console.log("err:",err.errors);
})
  • 如果所有的Promise都是reject的,那么會報一個AggregateError的錯誤。

二、手寫Promise

1.Promise的設計和構造方法

const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_REJECTED="rejected";
// * 自己手寫的Promise要符合的一定的規范,要符合PromiseA+
class HYPromise{
  // * 記錄狀態
  constructor(executor) {
    // * 保存Promise的狀態
    this.status=PROMISE_STATUS_PENDING;
    // * 保存傳入的值
    this.value=undefined;
    this.reason=undefined;
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        this.status=PROMISE_STATUS_FULFILLED;
        this.value=value;
        console.log("resolve被調用");
      }
     
    }
    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        console.log("reject被調用");
      }
     
    }
    executor(resolve,reject)
  }
}

const promise=new HYPromise((resolve,reject)=>{
  console.log("狀態pending");
  resolve("1111")
})

2.then方法的設計

 const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_REJECTED="rejected";
// * 自己手寫的Promise要符合的一定的規范,要符合PromiseA+
class HYPromise{
  // * 記錄狀態
  constructor(executor) {
    // * 保存Promise的狀態
    this.status=PROMISE_STATUS_PENDING;
    // * 保存傳入的值
    this.value=undefined;
    this.reason=undefined;
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        this.status=PROMISE_STATUS_FULFILLED;
        queueMicrotask(()=>{ //* 定時器是一個宏任務,會放在下一次事件循環時使用
        
          this.value=value;
          console.log("resolve被調用");
          // * 執行then傳入進來的第一個回調函數
          this.onFulfilled(this.value)
        
      })
      }
     
     
    }
    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        this.status=PROMISE_STATUS_REJECTED;
       queueMicrotask(()=>{
        this.reason=reason;
        console.log("reject被調用");
        // * 執行then傳入進來的第二個回調函數
        this.onRejected(this.reason);
       })
      }
     
    }
    executor(resolve,reject)
  }
  then(onFulfilled,onRejected){
    this.onFulfilled=onFulfilled;
    this.onRejected=onRejected;
  }
 
}

const promise=new HYPromise((resolve,reject)=>{
  console.log("狀態pending");
  // resolve("1111")
  reject("reject message")
})

promise.then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err:",err);
})

promise.then(res=>{
  console.log("res2:",res);
},err=>{
  console.log("err2:",err);
})

// * 多次調用then,后面的then方法會覆蓋前面的then方法,而且只會調用一次方法
// * then方法不能實現鏈式調用

3.then方法的優化一

  • 實現then多次調用
  • 如果Promise狀態已經確定,再次調用then方法,傳入的回調函數應該直接執行
 const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_REJECTED="rejected";
// * 自己手寫的Promise要符合的一定的規范,要符合PromiseA+
class HYPromise{
  // * 記錄狀態
  constructor(executor) {
    // * 保存Promise的狀態
    this.status=PROMISE_STATUS_PENDING;
    // * 保存傳入的值
    this.value=undefined;
    this.reason=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        queueMicrotask(()=>{ //* 定時器是一個宏任務,會放在下一次事件循環時使用
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          console.log("resolve被調用");
          // * 執行then傳入進來的第一個回調函數
         this.onFulfilledFns.forEach(Fn=>{
           Fn(this.value)
         })
        
      })
      }
     
     
    }
    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
       
       queueMicrotask(()=>{ 
         this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        console.log("reject被調用");
        // * 執行then傳入進來的第二個回調函數
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason)
        })
       })
      }
     
    }
    executor(resolve,reject)
  }
  then(onFulfilled,onRejected){
    // 1.如果then方法調用的時候,狀態已經確定下來了,應該直接執行的
    if(this.status===PROMISE_STATUS_FULFILLED&&onFulfilled){
      onFulfilled(this.value);
    }else if(this.status===PROMISE_STATUS_REJECTED&&onRejected){
      onRejected(this.reason)
    }else{
      // 將成功回調和失敗回調添加到數組中
    this.onFulfilledFns.push(onFulfilled);
    this.onRejectedFns.push(onRejected);
    }
    
  }
 
}

const promise=new HYPromise((resolve,reject)=>{
  console.log("狀態pending");
  resolve("1111");//resolved/fulfilled
})

promise.then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err:",err);
})

promise.then(res=>{
  console.log("res2:",res);
},err=>{
  console.log("err2:",err);
})



setTimeout(()=>{
  promise.then(res=>{
    console.log(res);
  })
},1000)

// * 解決了then方法的多次調用
// * 在確定Promise狀態之后,再次調用then
// const promise2=new Promise((resolve,reject)=>{
//   resolve("aaaaa");
// })

// setTimeout(()=>{
//   promise2.then(res=>{ //原生編寫了
//     console.log(res);
//   })
// },1000)

4.then方法的優化二

  • 實現了一個鏈式調用(返回一個新的Promise對象,使用新的Promise對象的resolve方法去處理對應的回調函數的返回值)
  • 實現了對executor執行時發生異常(錯誤),應該執行reject函數
  • 后面封裝了一個工具函數,用來處理異常和回調
 const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_REJECTED="rejected";

// 工具函數
function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    let result=exeFn(value);
    reject(result);
  }catch(err){
    reject(err);
  }
}
// * 自己手寫的Promise要符合的一定的規范,要符合PromiseA+
class HYPromise{
  // * 記錄狀態
  constructor(executor) {
    // * 保存Promise的狀態
    this.status=PROMISE_STATUS_PENDING;
    // * 保存傳入的值
    this.value=undefined;
    this.reason=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        // * 添加微任務
        queueMicrotask(()=>{ //* 定時器是一個宏任務,會放在下一次事件循環時使用
          if(this.status!==PROMISE_STATUS_PENDING) return;
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          // console.log("resolve被調用");
          // * 執行then傳入進來的第一個回調函數
         this.onFulfilledFns.forEach(Fn=>{
           Fn(this.value);
         })
        
      })
      }
     
     
    }
    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
      //  * 添加微任務
       queueMicrotask(()=>{ 
         if(this.status!==PROMISE_STATUS_PENDING) return;
         this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        // console.log("reject被調用");
        // * 執行then傳入進來的第二個回調函數
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason)
        })
       })
      }
     
    }

    // * 在調用executor時判斷里面是否拋出異常
    try{
      executor(resolve,reject)
    }catch(err){
      reject(err)
    }
  }
  then(onFulfilled,onRejected){
   
    return new HYPromise((resolve,reject)=>{
       // 1.如果then方法調用的時候,狀態已經確定下來了,應該直接執行的
    if(this.status===PROMISE_STATUS_FULFILLED&&onFulfilled){
      execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
    }else if(this.status===PROMISE_STATUS_REJECTED&&onRejected){
      execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
    }else{
      // 將成功回調和失敗回調添加到數組中
    this.onFulfilledFns.push(()=>{
      execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
    });
    this.onRejectedFns.push(()=>{
      execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
 });
    }
    })
  }
 
}

const promise=new HYPromise((resolve,reject)=>{
  // console.log("狀態pending");
  // resolve("1111");//resolved/fulfilled
  reject("2222")
  // throw new Error("創建就報的異常")
})

promise.then(res=>{
  console.log("res:",res);
  return "aaaa"

},err=>{
  console.log("err:",err);
  return "err bbb"
}).then(res=>{
  console.log("res2:",res);
},err=>{
  console.log("err2:",err);
})

// * 1. 實現了鏈式調用,鏈式調用的前提是返回一個新的HYPromise,最重要的是 什么時候執行resolve,什么時候執行reject
// * 一般在正常情況下,無論原HYPromise的狀態是如何,后面都會執行新的HYPromise的resolve,并將其值作為參數
// * 只有在代碼發生異常時(錯誤),才會讓新的HYPromise執行reject

// * 2. 在HYPromise的executor執行過程中如果發生異常,應該要執行reject


5.catch方法的設計

  • catch只會接受一個onRejected的回調函數
    • 在內部調用then方法,設置then方法的第一個參數為undefined,第二個參數的值為onRejected
  // * catch方法的設計
  catch(onRejected){
    this.then(undefined,onRejected);
  }

但是這樣還是不能捕獲原Promise對象的rejected狀態,因為這個catch方法是針對新的Promise的rejected的狀態,如果想要捕獲原Promise的rejected狀態,需要拋出異常,新的Promise對象的catch方法才能捕獲到。

所以我們需要改寫then方法:

  • 在方法內部前面判斷第二個參數是否有值,如果沒有值,就重新賦值為一個函數,函數內部拋出一個異常

這樣在新的Promise就能捕獲到原來的promise的rejected的狀態

 then(onFulfilled,onRejected){
   onRejected=onRejected||(err=>{throw err})
    //以下代碼省略...
  }

全部的代碼如下:

 const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_REJECTED="rejected";

// 工具函數
function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    let result=exeFn(value);
    reject(result);
  }catch(err){
    reject(err);
  }
}
// * 自己手寫的Promise要符合的一定的規范,要符合PromiseA+
class HYPromise{
  // * 記錄狀態
  constructor(executor) {
    // * 保存Promise的狀態
    this.status=PROMISE_STATUS_PENDING;
    // * 保存傳入的值
    this.value=undefined;
    this.reason=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        // * 添加微任務
        queueMicrotask(()=>{ //* 定時器是一個宏任務,會放在下一次事件循環時使用
          if(this.status!==PROMISE_STATUS_PENDING) return;
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          // console.log("resolve被調用");
          // * 執行then傳入進來的第一個回調函數
         this.onFulfilledFns.forEach(Fn=>{
           Fn(this.value);
         })
        
      })
      }
     
     
    }
    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
      //  * 添加微任務
       queueMicrotask(()=>{ 
         if(this.status!==PROMISE_STATUS_PENDING) return;
         this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        // console.log("reject被調用");
        // * 執行then傳入進來的第二個回調函數
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason)
        })
       })
      }
     
    }

    // * 在調用executor時判斷里面是否拋出異常
    try{
      executor(resolve,reject)
    }catch(err){
      reject(err)
    }
  }
  then(onFulfilled,onRejected){
   onRejected=onRejected||(err=>{throw err})
    return new HYPromise((resolve,reject)=>{
       // 1.如果then方法調用的時候,狀態已經確定下來了,應該直接執行的
    if(this.status===PROMISE_STATUS_FULFILLED&&onFulfilled){
      execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
    }else if(this.status===PROMISE_STATUS_REJECTED&&onRejected){
      execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
    }else{
      // 將成功回調和失敗回調添加到數組中
    if(onFulfilled)this.onFulfilledFns.push(()=>{
      execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
    });
    if(onRejected)this.onRejectedFns.push(()=>{
      execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
 });
    }
    })
  }
 
  // * catch方法的設計
  catch(onRejected){
    this.then(undefined,onRejected);
  }
}

const promise=new HYPromise((resolve,reject)=>{
  console.log("狀態pending");
  // resolve("1111");//resolved/fulfilled
  reject("2222")
  // throw new Error("創建就報的異常")
})


promise.then(res=>{
  console.log("res:",res);
},err=>{
  console.log("err1:",err);
}).catch(err=>{ 
  console.log("err:",err);
})

6.finally方法的設計

const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_REJECTED="rejected";

// 工具函數

function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    const result=exeFn(value);
    resolve(result);
  }catch(err){
    reject(err);
  }
}
class HYPromise{
  constructor(executor){
    this.status=PROMISE_STATUS_PENDING;
    this.value=undefined;
    this.reason=undefined;
    // this.onFulfilled=undefined;
    // this.onRejected=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        // * 原生執行then方法時是一個微任務
        queueMicrotask(()=>{
          if(this.status!==PROMISE_STATUS_PENDING) return; 
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          //  * 執行then傳入進來的回調函數
          // this.onFulfilled(this.value);
          this.onFulfilledFns.forEach(Fn=>{
            Fn(this.value);
          })
        })
      }
     
    }

    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
       queueMicrotask(()=>{
         if(this.status!==PROMISE_STATUS_PENDING) return; 
        this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        // * 執行then傳入進來的第二個參數
        // this.onRejected(this.reason);
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason);
        })
       })

     }
    }
    try{
    executor(resolve,reject)
    }catch(err){
      reject(err);
    }
    
  }

  then(onFulfilled,onRejected){
     onRejected=onRejected|| (err=>{ throw err});
     onFulfilled=onFulfilled|| (value=>value)
    return new HYPromise((resolve,reject)=>{
      if(this.status==PROMISE_STATUS_FULFILLED&&onFulfilled){
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
      }else if(this.status==PROMISE_STATUS_REJECTED&&onRejected){
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
      }else{
        if(onFulfilled)this.onFulfilledFns.push(()=>{
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
        });
        if(onRejected)this.onRejectedFns.push(()=>{
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
        });
      }
    })
   
  }
  catch(onRejected){
    return this.then(undefined,onRejected);
  }

  finally(onFinally){
    return this.then(()=>{
      onFinally();
    },()=>{
      onFinally();
    })
  }
}

const promise=new HYPromise((resolve,reject)=>{
  console.log("狀態pending");
  // reject("111");
  resolve("222");
  // throw new Error("pending err")
  
})


promise.then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("catch err:",err);
}).finally(()=>{
  console.log("finally方法實現");
})
// * 實現finally方法


7.類方法 resolve和reject的設計

const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_REJECTED="rejected";

// 工具函數

function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    const result=exeFn(value);
    resolve(result);
  }catch(err){
    reject(err);
  }
}
class HYPromise{
  constructor(executor){
    this.status=PROMISE_STATUS_PENDING;
    this.value=undefined;
    this.reason=undefined;
    // this.onFulfilled=undefined;
    // this.onRejected=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        // * 原生執行then方法時是一個微任務
        queueMicrotask(()=>{
          if(this.status!==PROMISE_STATUS_PENDING) return; 
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          //  * 執行then傳入進來的回調函數
          // this.onFulfilled(this.value);
          this.onFulfilledFns.forEach(Fn=>{
            Fn(this.value);
          })
        })
      }
     
    }

    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
       queueMicrotask(()=>{
         if(this.status!==PROMISE_STATUS_PENDING) return; 
        this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        // * 執行then傳入進來的第二個參數
        // this.onRejected(this.reason);
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason);
        })
       })

     }
    }
    try{
    executor(resolve,reject)
    }catch(err){
      reject(err);
    }
    
  }

  then(onFulfilled,onRejected){
     onRejected=onRejected|| (err=>{ throw err});
     onFulfilled=onFulfilled|| (value=>value)
    return new HYPromise((resolve,reject)=>{
      if(this.status==PROMISE_STATUS_FULFILLED&&onFulfilled){
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
      }else if(this.status==PROMISE_STATUS_REJECTED&&onRejected){
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
      }else{
        if(onFulfilled)this.onFulfilledFns.push(()=>{
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
        });
        if(onRejected)this.onRejectedFns.push(()=>{
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
        });
      }
    })
   
  }
  catch(onRejected){
    return this.then(undefined,onRejected);
  }

  finally(onFinally){
    return this.then(()=>{
      onFinally();
    },()=>{
      onFinally();
    })
  }
  static resolve(value){
    return new HYPromise((resolve,reject)=>{
      resolve(value);
    })
  }
  static reject(reason){
    return new HYPromise((resolve,reject)=>{
      reject(reason);
    })
  }
}

HYPromise.resolve(123).then(res=>{
  console.log("res:",res);
})

HYPromise.reject("err message").catch(err=>{
  console.log("err:",err);
})


// * 實現了類方法 resolve和reject方法

 

8. 類方法 all 和allSettled

const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_REJECTED="rejected";

// 工具函數

function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    const result=exeFn(value);
    resolve(result);
  }catch(err){
    reject(err);
  }
}
class HYPromise{
  constructor(executor){
    this.status=PROMISE_STATUS_PENDING;
    this.value=undefined;
    this.reason=undefined;
    // this.onFulfilled=undefined;
    // this.onRejected=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        // * 原生執行then方法時是一個微任務
        queueMicrotask(()=>{
          if(this.status!==PROMISE_STATUS_PENDING) return; 
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          //  * 執行then傳入進來的回調函數
          // this.onFulfilled(this.value);
          this.onFulfilledFns.forEach(Fn=>{
            Fn(this.value);
          })
        })
      }
     
    }

    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
       queueMicrotask(()=>{
         if(this.status!==PROMISE_STATUS_PENDING) return; 
        this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        // * 執行then傳入進來的第二個參數
        // this.onRejected(this.reason);
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason);
        })
       })

     }
    }
    try{
    executor(resolve,reject)
    }catch(err){
      reject(err);
    }
    
  }

  then(onFulfilled,onRejected){
     onRejected=onRejected|| (err=>{ throw err});
     onFulfilled=onFulfilled|| (value=>value)
    return new HYPromise((resolve,reject)=>{
      if(this.status==PROMISE_STATUS_FULFILLED&&onFulfilled){
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
      }else if(this.status==PROMISE_STATUS_REJECTED&&onRejected){
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
      }else{
        if(onFulfilled)this.onFulfilledFns.push(()=>{
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
        });
        if(onRejected)this.onRejectedFns.push(()=>{
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
        });
      }
    })
   
  }
  catch(onRejected){
    return this.then(undefined,onRejected);
  }

  finally(onFinally){
    return this.then(()=>{
      onFinally();
    },()=>{
      onFinally();
    })
  }
  static resolve(value){
    return new HYPromise((resolve,reject)=>{
      resolve(value);
    })
  }
  static reject(reason){
    return new HYPromise((resolve,reject)=>{
      reject(reason);
    })
  }
  static all(promises){
    // * 問題關鍵:什么時候執行resolve,什么時候執行reject
   return new HYPromise((resolve,reject)=>{
     let values=[];
      promises.forEach(promise=>{
        promise.then(res=>{
           values.push(res);
           if(values.length==promises.length) resolve(values);
        }).catch(err=>{
           reject(err);
        })
      })
   })
  }
  static allSettled(promises){
    
    return new Promise((resolve)=>{
      let results=[];
      promises.forEach(promise=>{
        promise.then(res=>{
          results.push({status:PROMISE_STATUS_FULFILLED,value:res})
          if(results.length==promises.length)
          resolve(results);
        }).catch(err=>{
          results.push({status:PROMISE_STATUS_REJECTED,value:err})
          if(results.length==promises.length)
          resolve(results);
        })
      })
    })
  }
}

const p1=new Promise((resolve)=>{
  setTimeout(()=>{
    resolve(1111)
  },1000)
})

const p2=new Promise((resolve)=>{
  setTimeout(()=>{
    resolve(2222)
  },2000)
})

const p3=new Promise((resolve)=>{
  setTimeout(()=>{
    resolve(3333)
  },3000)
})
// *all方法會產生一個新的Promise對象,這個新的Promise對象是由前面的所有的Promise來決定其狀態
// * 如果全部為fulfilled,則會執行then方法,如果有一個為rejected,則直接執行catch方法
HYPromise.all([p1,p2,p3]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})


// * allSettled:它會等所有的Promise都有結果,然后再執行resolve方法,它是沒有reject方法的執行
// * 實現了all方法:

HYPromise.allSettled([p1,p2,p3]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err);
})
 

9. 類方法 race和any

const PROMISE_STATUS_FULFILLED="fulfilled";
const PROMISE_STATUS_PENDING="pending";
const PROMISE_STATUS_REJECTED="rejected";

// 工具函數

function execFunctionWithCatchError(exeFn,value,resolve,reject){
  try{
    const result=exeFn(value);
    resolve(result);
  }catch(err){
    reject(err);
  }
}
class HYPromise{
  constructor(executor){
    this.status=PROMISE_STATUS_PENDING;
    this.value=undefined;
    this.reason=undefined;
    // this.onFulfilled=undefined;
    // this.onRejected=undefined;
    this.onFulfilledFns=[];
    this.onRejectedFns=[];
    const resolve=(value)=>{
      if(this.status==PROMISE_STATUS_PENDING){
        // * 原生執行then方法時是一個微任務
        queueMicrotask(()=>{
          if(this.status!==PROMISE_STATUS_PENDING) return; 
          this.status=PROMISE_STATUS_FULFILLED;
          this.value=value;
          //  * 執行then傳入進來的回調函數
          // this.onFulfilled(this.value);
          this.onFulfilledFns.forEach(Fn=>{
            Fn(this.value);
          })
        })
      }
     
    }

    const reject=(reason)=>{
      if(this.status==PROMISE_STATUS_PENDING){
       queueMicrotask(()=>{
         if(this.status!==PROMISE_STATUS_PENDING) return; 
        this.status=PROMISE_STATUS_REJECTED;
        this.reason=reason;
        // * 執行then傳入進來的第二個參數
        // this.onRejected(this.reason);
        this.onRejectedFns.forEach(Fn=>{
          Fn(this.reason);
        })
       })

     }
    }
    try{
    executor(resolve,reject)
    }catch(err){
      reject(err);
    }
    
  }

  then(onFulfilled,onRejected){
     onRejected=onRejected|| (err=>{ throw err});
     onFulfilled=onFulfilled|| (value=>value)
    return new HYPromise((resolve,reject)=>{
      if(this.status==PROMISE_STATUS_FULFILLED&&onFulfilled){
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
      }else if(this.status==PROMISE_STATUS_REJECTED&&onRejected){
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
      }else{
        if(onFulfilled)this.onFulfilledFns.push(()=>{
        execFunctionWithCatchError(onFulfilled,this.value,resolve,reject);
        });
        if(onRejected)this.onRejectedFns.push(()=>{
        execFunctionWithCatchError(onRejected,this.reason,resolve,reject);
        });
      }
    })
   
  }
  catch(onRejected){
    return this.then(undefined,onRejected);
  }

  finally(onFinally){
    return this.then(()=>{
      onFinally();
    },()=>{
      onFinally();
    })
  }
  static resolve(value){
    return new HYPromise((resolve,reject)=>{
      resolve(value);
    })
  }
  static reject(reason){
    return new HYPromise((resolve,reject)=>{
      reject(reason);
    })
  }
  static all(promises){
    // * 問題關鍵:什么時候執行resolve,什么時候執行reject
   return new HYPromise((resolve,reject)=>{
     let values=[];
      promises.forEach(promise=>{
        promise.then(res=>{
           values.push(res);
           if(values.length==promises.length) resolve(values);
        }).catch(err=>{
           reject(err);
        })
      })
   })
  }
  static allSettled(promises){
    
    return new HYPromise((resolve)=>{
      let results=[];
      promises.forEach(promise=>{
        promise.then(res=>{
          results.push({status:PROMISE_STATUS_FULFILLED,value:res})
          if(results.length==promises.length)
          resolve(results);
        }).catch(err=>{
          results.push({status:PROMISE_STATUS_REJECTED,value:err})
          if(results.length==promises.length)
          resolve(results);
        })
      })
    })
  }

  static race(promises){
    return new HYPromise((resolve,reject)=>{
      promises.forEach(promise=>{
        // promise.then(res=>{
        //   resolve(res);
        // }).catch(err=>{
        //   reject(err);
        // })
        promise.then(resolve,reject)
      })
    })
  }
  static any(promises){
    // * resolve必須等待有一個成功的結果
    // * reject 所有的都失敗才執行 reject
    return new HYPromise((resolve,reject)=>{
      let count=0;
      let reasons=[];
      promises.forEach(promise=>{
        promise.then(res=>{
          resolve(res)
        }).catch(err=>{
          reasons.push(err);
          if(reasons.length==promises.length){
            
            // reject(reasons)
            reject(new AggregateError(reasons," AggregateError: All promises were rejected"))
          }
        })
      })
    })
  }
}

// const p1=new Promise((resolve)=>{
//   setTimeout(()=>{
//     resolve(1111)
//   },1000)
// })

// const p2=new Promise((resolve)=>{
//   setTimeout(()=>{
//     resolve(2222)
//   },2000)
// })

// const p3=new Promise((resolve)=>{
//   setTimeout(()=>{
//     resolve(3333)
//   },3000)
// })

// HYPromise.race([p1,p2,p3]).then(res=>{
//   console.log("res:",res);
// }).catch(err=>{
//   console.log("err:",err);
// })

// * any方法
const p1=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(1111)
  },1000)
})

const p2=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(2222)
  },2000)
})

const p3=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    reject(3333)
  },3000)
})

HYPromise.any([p1,p2,p3]).then(res=>{
  console.log("res:",res);
}).catch(err=>{
  console.log("err:",err.errors);
})

三、總結

Promise.png
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內容