要解決這個問題,首先要知道Promise.all是什么?
-
Promise.all() 它接收一個promise對象組成的數組作為參數,並返回一個新的promise對象。
-
當數組中所有的對象都resolve時,新對象狀態變為fulfilled,所有對象的resolve的value依次添加組成一個新的數組,並以新的數組作為新對象resolve的value。
-
當數組中有一個對象reject時,新對象狀態變為rejected,並以當前對象reject的reason作為新對象reject的reason。
我們用setTimeout來模擬請求,數據data = [500, 400, 300, 200, 100]既是每個請求返回的數據也是每個請求所需的時間。
如果是繼發請求(一個請求結束后再請求后一個),那么應該是按順序打印,理論上所有請求的總時間等於每個請求所花時間之和,約等於1500ms;如果是並發請求(假設請求數不會太多,不超過限制),順序是按時間從小到大打印,理論上所有請求的總時間等於最長的那個時間,約等於500ms
// 模擬請求
function request(param) {
return new Promise(resolve => {
setTimeout(() => {
console.log(param)
resolve()
}, param)
})
}
const items = [500, 400, 300, 200, 100]
使用Promise.all可以並發執行,並知道請求結束。
(() => {
Promise.all(items.map(request)).then(res => {
console.log('end')
})
})()
// 輸出:100, 200, 300, 400, 500, end
但是由Promise.all的定義知道,當其中一個出錯時,就不會resolve返回值。
模擬一個出錯的情況
const items = [500, 400, 300, 200, 100]
function request(param) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (param === 200) {
// console.log(param, ' failed')
return reject({
status: 'error',
data: param
})
}
// console.log(param, ' success')
resolve({
status: 'success',
data: param
})
}, param)
})
}
出錯時,在使用剛剛那個Promise.all時就會打印
(() => {
Promise.all(items.map(request))
.then(res => {
console.log(res)
})
.catch (err => {
console.log(err)
})
.finally(res => {
console.log('end', res)
})
})()
// 輸出 {status: "error", data: 200}, end, undefined
上面的輸出可以看出,如果有錯誤,則不會進入then,而是進入catch,然后進入finally,但是finally不接受參數,只告訴你結束了。如果把上面模擬請求的console.log(...)注釋去掉,還會發現finally是在catch結束后就執行了,而200后面的請求還未結束。
接下來我們改造下模擬請求,在請求出錯后就catch錯誤
使用catch捕獲錯誤,然后就能再執行catch后面的正確函數,不使用catch捕獲錯誤,一旦出錯,就會停止繼續執行正確函數。
const items = [500, 400, 300, 200, 100]
// 請求出錯時,catch錯誤就可以。當出錯時,仍能按順序執行並輸出。
function request(param) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (param === 200) {
// console.log(param, ' failed')
return reject({
status: 'error',
data: param
})
}
// console.log(param, ' success')
resolve({
status: 'success',
data: param
})
}, param)
}).catch(err => err)
}
// 輸出 [{…}, {…}, {…}, {stauts: 'error', data: 200}, {…}], end
這樣就解決了我們的問題了。