今日一題 - 請模擬實(shí)現(xiàn)一個(gè)Promise.all() 方法?

對Promise.all 的理解
Promise.all()方法用于將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例。
Promise.all()方法的參數(shù)可以不是數(shù)組,但必須具有 Iterator 接口(所以數(shù)組、Map、Set都可以),并且只返回一個(gè)Promise實(shí)例,輸入的所有promise的resolve回調(diào)的結(jié)果會(huì)按傳入的按順序作為一個(gè)數(shù)組的其中一項(xiàng)返回。
當(dāng)然也支持非promise對象的傳入,會(huì)作為數(shù)組中的一項(xiàng)返回。
返回結(jié)果的兩個(gè)特點(diǎn)
全部成功一起返回:當(dāng)接收的所有Promise實(shí)例都執(zhí)行成功后才會(huì)返回結(jié)果,返回的結(jié)果是一個(gè)數(shù)組,返回值將會(huì)按照參數(shù)內(nèi)的 promise 順序排列,而不是由調(diào)用 promise 的完成順序決定。
失敗快速返回:當(dāng)其中一個(gè)Promise實(shí)例執(zhí)行失敗了就會(huì)立刻返回,只返回失敗的結(jié)果,不會(huì)管其他promise執(zhí)行的結(jié)果。
使用方式 - promise 實(shí)例全部成功一起返回
let?p1?=?new?Promise((resolve,?reject)?=>?{
??resolve('p1')
})
let?p2?=?new?Promise((resolve,?reject)?=>?{
??resolve('p2')
})
let?p3?=?new?Promise((resolve,?reject)?=>?{
??resolve('p3')
})
//全部成功的情況,接收p1?p2,?p3
Promise.all([p1,?p2,?p3]).then(results?=>?{
??console.log(results)
}).catch(error?=>?{
??console.log(error)
})

使用方式 - 失敗快速返回
即便是最后一個(gè)promise 失敗了,也會(huì)提前返回,不會(huì)等待前面的promise返回.
var?p1?=?new?Promise((resolve,?reject)?=>?{
??setTimeout(resolve,?1000,?'one');
});
var?p2?=?new?Promise((resolve,?reject)?=>?{
??setTimeout(resolve,?2000,?'two');
});
var?p3?=?new?Promise((resolve,?reject)?=>?{
??setTimeout(resolve,?3000,?'three');
});
var?p4?=?new?Promise((resolve,?reject)?=>?{
??setTimeout(resolve,?4000,?'four');
});
var?p5?=?new?Promise((resolve,?reject)?=>?{
??reject('reject');
});
Promise.all([p1,?p2,?p3,?p4,?p5]).then(values?=>?{
??console.log(values);
},?reason?=>?{
??console.log(reason)
});
如果傳入的是非promise對象呢?
如果參數(shù)中包含非 promise 值,這些值將被忽略,但仍然會(huì)被放在返回?cái)?shù)組中.
var?p?=?Promise.all([1,2,3]);
var?p2?=?Promise.all([1,2,3,?Promise.resolve(4)]);
var?p3?=?Promise.all([1,2,3,?Promise.reject(5)]);
setTimeout(function(){
????p.then(res=>console.log(res))
?????p2.then(res=>console.log(res))
?????p3.then(res=>console.log(res))
});

錯(cuò)誤處理
因?yàn)镻roims.all() 結(jié)果返回的是一個(gè) promise對象,所以和普通的promise錯(cuò)誤處理是一樣的。
可以通過reject或者catch來進(jìn)行捕獲。
?//1?catch
?//....
?Promise.all([p1,?p2,p3]).then(results?=>?{
????console.log(results)????//?['p1',?'p2']
??}).catch(error?=>?{
????//錯(cuò)誤捕獲
????console.log(error)
??})
??
?//2?reject
?//....
?Promise.all([p1,?p2,p3]).then(results?=>?{
????console.log(results)????//?['p1',?'p2']
??},(error){
?//錯(cuò)誤捕獲
??console.log(error)
})
模擬實(shí)現(xiàn)
上面的幾個(gè)特點(diǎn)就是我們思考的入口,也是必須要滿足的條件。
多個(gè)promise最后返回一個(gè)promise 必須全部成功才會(huì)返回 失敗會(huì)優(yōu)先返回,不會(huì)等他promise結(jié)果
?function?customerPromiseAll(promises)?{
????return?new?Promise((resolve,?reject)?=>?{
??????let?resultCount?=?0;?//計(jì)數(shù)器
??????let?promiseLen?=?promises.length;?//傳入的promise個(gè)數(shù)
??????let?results?=?new?Array(promiseLen);//初始化數(shù)組用于存放返回結(jié)果
?
??????//按順序執(zhí)行
??????for?(let?i?=?0;?i?????????promises[i].then(value?=>?{
??????????resultCount++;
??????????results[i]?=?value;?//保證執(zhí)行結(jié)果的順序
??????????if?(resultCount?===?promises.length)?{
????????????return?resolve(results)?//執(zhí)行完最后一個(gè)promise,則返回
??????????}
????????},?error?=>?{
??????????reject(error)?//執(zhí)行錯(cuò)誤直接reject
????????})
??????}
????})
??}
驗(yàn)證一下
??let?p1?=?new?Promise(resolve?=>?resolve('p1'))
??let?p2?=?new?Promise(resolve?=>?resolve('p2'))
??let?p3?=?Promise.reject('p3?error')
??customerPromiseAll([p1,?p2]).then(results?=>?{
????console.log(results)????//?['p1',?'p2']
??}).catch(error?=>?{
????console.log(error)
??})
??customerPromiseAll([p1,?p2,?p3]).then(results?=>?{
????console.log(results)
??}).catch(error?=>?{
????console.log(error)??????//?'p3?error'
??})
驗(yàn)證通過,結(jié)果沒啥毛病,符合預(yù)期。
支持非promise對象
上面我們驗(yàn)證傳入都是常規(guī)的promise對象,如果傳入非promise對象呢?
customerPromiseAll([1,2,3])?//emmm?.直接報(bào)錯(cuò)了

所以我們需要增加驗(yàn)證傳入的值是不是promise,非promise對象,則直接resolve。
//驗(yàn)證是否是promise對象
function?isPromise(obj)?{
??return?!!obj??//有實(shí)際含義的變量才執(zhí)行方法,變量null,undefined和''空串都為false
???&&?(typeof?obj?===?'object'?||?typeof?obj?===?'function')?//?初始promise?或?promise.then返回的
???&&?typeof?obj.then?===?'function';
}
完整代碼 1 非promise 對下直接存入數(shù)組
function?customerPromiseAll(promises)?{
????return?new?Promise((resolve,reject)=>{
????????let?resultCount?=?0;
????????//計(jì)數(shù)器
????????let?promiseLen?=?promises.length;
????????//傳入的promise個(gè)數(shù)
????????let?results?=?new?Array(promiseLen);
????????//初始化數(shù)組用于存放返回結(jié)果
????????//按順序執(zhí)行
????????for?(let?i?=?0;?i?????????????if?(!isPromise(promises[i]))?{
????????????????resultCount++;
????????????????results[i]?=?promises[i];?//直接存儲(chǔ)結(jié)果
????????????????if?(resultCount?===?promiseLen)?{
????????????????????return?resolve(results)
????????????????????//執(zhí)行完最后一個(gè)promise,則返回
????????????????}
????????????}?else?{
????????????????promises[i].then(value=>{
????????????????????resultCount++;
????????????????????results[i]?=?value;?//存儲(chǔ)resolve的結(jié)果
????????????????????//保證執(zhí)行結(jié)果的順序
????????????????????if?(resultCount?===?promiseLen)?{
????????????????????????return?resolve(results)
????????????????????????//執(zhí)行完最后一個(gè)promise,則返回
????????????????????}
????????????????}
????????????????,?error=>{
????????????????????reject(error)
????????????????????//執(zhí)行錯(cuò)誤直接reject
????????????????}
???????????????)
????????????}
????????}
????}
???)
}
完整代碼2 非promise對象調(diào)用Promise.resolve()返回一個(gè)promise對象
function?customerPromiseAll(promises)?{
????return?new?Promise((resolve,reject)=>{
????????let?resultCount?=?0;
????????//計(jì)數(shù)器
????????let?promiseLen?=?promises.length;
????????//傳入的promise個(gè)數(shù)
????????let?results?=?new?Array(promiseLen);
????????//初始化數(shù)組用于存放返回結(jié)果
????????//按順序執(zhí)行
????????for?(let?i?=?0;?i?????????????let?curPromise?=?promises[i]
????????????if?(!isPromise(curPromise))?{
????????????????curPromise?=?Promise.resolve(curPromise)
????????????}
????????????curPromise.then(value=>{
????????????????resultCount++;
????????????????results[i]?=?value;
????????????????//存儲(chǔ)resolve的結(jié)果
????????????????//保證執(zhí)行結(jié)果的順序
????????????????if?(resultCount?===?promiseLen)?{
????????????????????return?resolve(results)
????????????????????//執(zhí)行完最后一個(gè)promise,則返回
????????????????}
????????????}
????????????,?error=>{
????????????????reject(error)
????????????????//執(zhí)行錯(cuò)誤直接reject
????????????}
???????????)
????????}
????}
???)
}
最后
平時(shí)對Promise.all方法只是處于使用的層面,其實(shí)深挖一下的話收獲還是很多的。
今天就到這里,希望對你有用。
點(diǎn)個(gè)『在看』支持下?
