一、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方法傳入的回調函數。
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(()=>{
})
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)
})
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("------");
})
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);
})
這個代碼運行后會報錯的。
- 之間不會相互影響的
- 因為在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);
})