今天來分享一個之前同事問我的問題,因為我們工作上很常用到的是 fetch 或是 request,這種需要多發 request 的情境,但發 request 有一個問題就是 request 發送有機會不成功,那這樣使用 Promise.all 就會跑到一半停止讓整個流程變得很難處理。所以就來說明我們應該怎麼解決這個問題。
Promise 失敗彈出 catch
首先我們先用 setTimeout 來製作一個需要等待 1 sec,但是會發生 catch 的例子來模擬情境:
const wait = new Promise((resolve, reject) => {
setTimeout(() => {
reject('reject err');
}, 1000)
});
function promiseAll(promises) {
return Promise.all(promises).then(res => {
console.log(`res: ${res}`);
}).catch(err => {
console.log(`err: ${err}`);
});
};
const waitArray = [];
waitArray.push(wait);
waitArray.push(wait);
promiseAll(waitArray);
從上面範例可以看到,我製作了一個叫做 wait 的 Promise function,使用 waitArray 把它裝起來,放入 promiseAl,這樣寫是希望想要得到執行兩次 wait function 的結果,那我們來執行一下:
clarence ~ $ node index.js err: reject err
很明顯我們原本希望可以執行兩次 wait function,但是因為 catch 的關係 Promise.all 直接吐出 catch 中斷了第二個 wait function。
解決 Promise 失敗被 catch 的問題
OK! 我們現在清楚我們要解決的問題了,那我們來把 wait function 包一層起來讓它不要噴出 catch 感覺就可以解決這個問題了。
一開始先處理單個,包完應該會如下:
const wait = new Promise((resolve, reject) => {
setTimeout(() => {
reject('reject err');
}, 1000)
})
const catchPromise = wait.then(res => res).catch(err => err);
catchPromise.then(res => {
console.log(`res: ${res}`);
}).catch(err => {
console.log(`err: ${err}`);
});
一樣我們來執行一下!
clarence ~ $ node index.js res: reject err
OK! 跟預期的依樣,我們讓他在執行 Promise 的時候不要彈到 catch ,剩下就是把它改成多個的情況。
解決 Promise.all 失敗被 catch 的問題
const wait = new Promise((resolve, reject) => {
setTimeout(() => {
reject('reject err');
}, 1000)
})
const waitArray = [];
waitArray.push(wait);
waitArray.push(wait);
const catchPromiseMap = (promises) => {
return promises.map(promise => {
return promise.then(res => res).catch(err => err);
});
}
const promiseArray = catchPromiseMap(waitArray);
Promise.all(promiseArray).then(res => {
console.log(`res: ${res}`);
}).catch(err => {
console.log(`err: ${err}`);
});
來執行一下吧!
clarence ~ $ node index.js res: reject err,reject err
OK! 太棒了!成功拉 ~ 我們終於實現一個使用 Promise all,但是不會因為 catch 抓到而失敗的方法了!