一文詳解如何有效的處理Promise并發(fā)
前言
如上圖所示的代碼,相信大家在平時的開發(fā)中肯定用到不少,我們可以進行優(yōu)化,使得只用短短一半的時間就可以完成。 在上面的函數(shù)中,我們等待用戶信息請求完成后再請求詳情信息。但這兩個函數(shù)之間并沒有任何關(guān)聯(lián),所以我們可以同時觸發(fā)兩個請求,并同時等待完成。那么,我們有多少種方式來實現(xiàn)呢?你真的可以處理好Promise
的并發(fā)么?接下來,我們進入正題。
Promise.all
如何實現(xiàn)
Promise.all 大家應該是比較熟悉的,Promise.all
方法接收一個promise
的iterable
類型,如果所有傳入的promise
都變成完成狀態(tài),Promise.all
返回的Promise異步的變?yōu)橥瓿?。如果傳入?code>promise中有一個失敗(rejected
),Promise.all
將失敗的結(jié)果給失敗狀態(tài)的回調(diào)函數(shù),而不管其他promise
是否完成。 我們可以如下實現(xiàn)剛才的代碼
async function init() { const [user, info] = await Promise.all([ getUser(), getInfo() ]) console.log('init', user, info) }
現(xiàn)在這種方式,如果我們之前每個請求都需要1秒,一共需要2秒,那么現(xiàn)在兩個同時執(zhí)行只需要1秒就完成了!但是這樣也有一個問題:我們并沒有考慮報錯問題。你可能會認為,這個很簡單,把代碼放在一個try...cahtch
中不就可以了,就像這樣:
async function init() { try { const [user, info] = await Promise.all([ getUser(), getInfo() ]) console.log('init ==== ', user, info) } catch(err) { console.log('err', err); } }
但是,這樣的話會有一個問題,就像這樣:
function getUser() { return new Promise((resolve, reject) => { setTimeout(() => { reject('user reject') }, 500); }) } function getInfo() { return new Promise((resolve, reject) => { setTimeout(() => { reject('info reject') }, 1000); }) } // 輸出 err user reject
由于getUser
優(yōu)先完成并出現(xiàn)錯誤,此時觸發(fā)了catch
,而當getInfo
再次完成并出現(xiàn)錯誤時,將不會觸發(fā)catch
。因為catch
代碼已經(jīng)運行,函數(shù)已經(jīng)完成。 那么,要怎么做呢?接下來,我們就講講應該如何處理報錯問題。
如何處理報錯
解決方式是,給Promise.all
中的每個函數(shù)加上catch
,如下:
function handle(err) { console.log('err', err) } function onReject(err) { handle(err); return new Error(err); } async function init() { const [user, info] = await Promise.all([ getUser().catch(onReject), getInfo().catch(onReject) ]) console.log('init', user instanceof Error, info instanceof Error) // init true true }
這樣,我們在onReject
函數(shù)中處理錯誤,并返回這個錯誤。所以現(xiàn)在我們生成的user
和info
要么是Error
要么是我們期望的效果,而Error
我們可以用instanceof
檢查它。
Promise.allSettled
解決并發(fā)我們還可以使用 Promise.allSettled ,我們會得到一個包含每個Promise
結(jié)果的值或錯誤信息。
如何實現(xiàn)
接下來,我們來使用一下,代碼如下:
async function init() { const [userStatus, infoStatus] = await Promise.allSettled([ getUser(), getInfo() ]) console.log('info', userStatus, infoStatus) }
現(xiàn)在,我們可以得到這樣的數(shù)據(jù):
結(jié)果對象有3個屬性:
- status:
fulfilled
或rejected
- value: 僅在
status
為fulfilled
時出現(xiàn),為Promise
為resolve
返回的值 - reason: 僅在
status
為rejected
時出現(xiàn),為Promise
被reject
時返回的值
因此,我們可以讀取到每個Promise
的狀態(tài),并單獨處理每個錯誤而不會遺漏任何的信息。
最后兩個技巧
Promise.race
Promise.race方法可接受一個可迭代的promise
返回一個promise
,一旦迭代器中某個promise
解決或拒絕,返回的promise
就會resolve
或reject
。
我們可以這樣實現(xiàn)一個簡單的超時功能,代碼如下:
function getUser() { return new Promise((resolve) => { setTimeout(() => { resolve('user resolve') }, 5100); }) } async function init() { // Race to see which Promise completes first const racePromise = Promise.race([ getUser(), new Promise((resolve, reject) => // Time out after 5 seconds setTimeout(() => reject(new Error('Timeout')), 5000) ) ]) try { const result = await racePromise console.log('result', result) } catch (err) { console.log('err', err) // Timed out! } }
注意,通常情況下,如果有超時,那么你需要盡量的取消未完成的待處理任務(wù)。
另外,最好還是處理所有promise
的reject
:
const racePromise = Promise.race([ getUser().catch(onReject), // xxx ])
Promise.any
Promise.any 等待任何一個promise
成功則為成功,只有全部的promise
都被reject
,才會返回reject
。通常我們可以使用Promise.any
來實現(xiàn),當一個promise
先完成后,取消其他的promise
,不過要注意的是,我們并不總是同時要處理多個數(shù)據(jù),只是因為我們可以做到,所以要謹慎的使用它。
通常,我們不想出現(xiàn)未被處理的reject
,所以,我們應該這樣寫:
const anyPromise = Promise.any([ getUser().catch(onReject), getInfo().catch(onReject) ])
總結(jié)
前面我們已經(jīng)介紹了在使用promise
處理并發(fā)問題時,應該如何的處理promise
的reject
。但是也需要注意:過度的并發(fā)會導致網(wǎng)絡(luò)抖動、磁盤抖動或其他問題,雖然可以,但并不是一定要這樣做,有時使用async await
也可以使代碼更容易理解和維護,所以,在使用之前我們更需要考慮是否需要。
以上就是一文詳解如何有效的處理Promise并發(fā)的詳細內(nèi)容,更多關(guān)于有效處理Promise并發(fā)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript中的普通函數(shù)和箭頭函數(shù)的區(qū)別和用法詳解
這篇文章主要介紹了JavaScript中的普通函數(shù)和箭頭函數(shù)的區(qū)別和用法詳解,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-03-03利用webpack理解CommonJS和ES Modules的差異區(qū)別
這篇文章主要介紹了利用webpack理解CommonJS和ES Modules的差異區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-06-06JavaScript基于對象方法實現(xiàn)數(shù)組去重及排序操作示例
這篇文章主要介紹了JavaScript基于對象方法實現(xiàn)數(shù)組去重及排序操作,涉及javascript基于對象方法的數(shù)組遍歷、比較、去重、排序等相關(guān)操作技巧,需要的朋友可以參考下2018-07-07