await/async無(wú)法捕獲與處理錯(cuò)誤信息的解決方案分享
前言
如果你對(duì)同步任務(wù)/異步任務(wù)/回到地獄/promise概念/async-await的作用不是很了解的話,或許需要看一下以下簡(jiǎn)單的介紹。
如果都了解則可以直接點(diǎn)擊側(cè)邊欄跳到下面看await無(wú)法處理錯(cuò)誤信息的解決方案。
同步和異步
javascript是一個(gè)單線程的語(yǔ)言。因?yàn)槭菃尉€程。所以這直接導(dǎo)致了線程阻塞的問(wèn)題,在前一個(gè)任務(wù)完成以前,后面所有的任務(wù)都無(wú)法執(zhí)行。因?yàn)檫@個(gè)問(wèn)題。所以javascript有了異步任務(wù)的概念。
javascript把其中的任務(wù)分為兩部分,一種是同步任務(wù),一種是異步任務(wù),一些可能造成阻塞的任務(wù)歸為異步任務(wù),并將異步任務(wù)放到所有的同步任務(wù)之后去執(zhí)行,以解決阻塞問(wèn)題。
常見的異步任務(wù)有
- settimeout/setInterval
- Promise的then函數(shù)
- XMLHttpRequest(http請(qǐng)求也就是ajax)
異步任務(wù)解決了執(zhí)行堵塞的問(wèn)題,同時(shí)也存在一些問(wèn)題(如下)。
異步任務(wù)所存在的問(wèn)題
異步任務(wù)需要回調(diào)來(lái)處理任務(wù)結(jié)束以后的一些動(dòng)作。在一些特殊場(chǎng)景下,有些異步任務(wù)需要依賴于其他異步任務(wù)的回調(diào)。這就需要將需要依賴的異步任務(wù)寫到被依賴的異步任務(wù)的回調(diào)中。
這是一種解決依賴異步依賴的方案,雖然可行,但不可讀。 總會(huì)出現(xiàn)依賴層級(jí)較多的情況,大量的層級(jí)會(huì)讓這個(gè)功能變得非常晦澀??勺x性極差。如下??

雖然一般開發(fā)中很少會(huì)出現(xiàn)這種嵌套7層的異步任務(wù)。但嵌套3,4層還是相對(duì)常見的。多層的嵌套配合本身存在的邏輯。對(duì)代碼的閱讀非常不友好。前端工程師們?yōu)榱私鉀Q這個(gè)問(wèn)題。在ES6中推出了Promise。
Promise如何解決回調(diào)地獄
Promise提供resolve和reject兩個(gè)函數(shù)來(lái)代表異步任務(wù)的成功和失敗。最關(guān)鍵的一點(diǎn)是Promise提供了.then()和.catch()函數(shù),.then()函數(shù)負(fù)責(zé)處理異步任務(wù)成功后的動(dòng)作,.catch()負(fù)責(zé)處理異步任務(wù)失敗后的動(dòng)作。
他們?cè)谝欢ǔ潭壬蟽?yōu)化了回調(diào)地獄

Promise還可以進(jìn)行鏈?zhǔn)秸{(diào)用

雖然Promise對(duì)于地獄回調(diào)有所改善。但他依然有著一定的嵌套結(jié)構(gòu)存在。有沒有什么方案可以徹底脫離嵌套結(jié)構(gòu)?
有
es6后來(lái)又推出了async/await(Promise的語(yǔ)法糖)。
async/await,回調(diào)地獄的最終方案
async/await完全解決了回調(diào)嵌套的問(wèn)題。實(shí)現(xiàn)了以看似同步的代碼,完成異步的需求。
async右邊的函數(shù)會(huì)返回一個(gè)Promise對(duì)象。如圖??

await是等待一個(gè)async函數(shù)執(zhí)行完畢,并提取Promise中的值。??

這樣,我們就擺脫了嵌套結(jié)構(gòu)的問(wèn)題?,F(xiàn)在我們來(lái)看下整套一起使用。

async/await錯(cuò)誤處理方案
async/await作為promise的語(yǔ)法糖。它徹底解決了回調(diào)地獄的問(wèn)題,但也存在一個(gè)問(wèn)題。相對(duì)于Promise的鏈?zhǔn)秸{(diào)用。async/await無(wú)法捕獲錯(cuò)誤。普通的Promise是通過(guò).catch()和reject()配合來(lái)進(jìn)行錯(cuò)誤程序處理。但是async/await并沒有在語(yǔ)法內(nèi)部提供錯(cuò)誤處理。
這就導(dǎo)致了如果異步請(qǐng)求錯(cuò)誤,我們無(wú)法做出相應(yīng)補(bǔ)救措施而且錯(cuò)誤信息會(huì)在控制臺(tái)打印。


現(xiàn)在我們常規(guī)await的處理方案有以下幾種。
第一種,手動(dòng)添加啊try{}catch{}進(jìn)行捕獲
我們可以通過(guò)手動(dòng)給async函數(shù)內(nèi)部添加*try{}catch{}*來(lái)進(jìn)行錯(cuò)誤捕獲,如此,就可以避免錯(cuò)誤在控制臺(tái)打印和阻塞代碼的運(yùn)行。如下

這種做法的弊端是:需要捕獲錯(cuò)誤的async多的話。每一個(gè)都寫下去,就比較麻煩和不可讀了。
第二種,使用await-to-js庫(kù)
網(wǎng)上總有大牛幫我們解決這些問(wèn)題。await-to-js是一個(gè)幫助我們解決異步錯(cuò)誤處理的庫(kù),知名度較高,到目前有2.7k的?。
import to from "await-to-js";
//模擬請(qǐng)求
const handleFetch = async () => {
fetch("/url",{})
}
//進(jìn)行錯(cuò)誤捕獲和處理
const [err, result] = await to(handleFetch());
if (err) {
//進(jìn)行錯(cuò)誤動(dòng)作處理
}這是一種比較簡(jiǎn)單的處理方式
源碼 ---ts版本
| --- | ------------------------------------------------------------------------------------- |
| | * @param { Promise } promise |
| | * @param { Object= } errorExt - Additional Information you can pass to the err object |
| | * @return { Promise } |
| | */ |
| | export function to<T, U = Error> ( |
| | promise: Promise<T>, |
| | errorExt?: object |
| | ): Promise<[U, undefined] | [null, T]> { |
| | return promise |
| | .then<[null, T]>((data: T) => [null, data]) |
| | .catch<[U, undefined]>((err: U) => { |
| | if (errorExt) { |
| | const parsedError = Object.assign({}, err, errorExt); |
| | return [parsedError, undefined]; |
| | } |
| | |
| | return [err, undefined]; |
| | }); |
| | } |
| | |
| | export default tots版本的源碼可能不便于閱讀,以下是我翻譯成js版本的源碼 ,并附加注解
export function to(
promise,
errorExt,
) {
return promise
//成功,則error返回null,result返回data
.then((data) => [null, data])
//錯(cuò)誤則捕獲錯(cuò)誤內(nèi)容,然后返回錯(cuò)誤信息,result為undefined
.catch((err) => {
if (errorExt) {
const parsedError = Object.assign({}, err, errorExt);
return [parsedError, undefined];
}
return [err, undefined];
});
}最后
相較于自己使用try和catch進(jìn)行捕獲,我更喜歡使用await-to-js這個(gè)庫(kù),簡(jiǎn)單方便,而且貼近hooks的寫法讓我覺得親切。
是否有必要給每一個(gè)請(qǐng)求都加上一個(gè)錯(cuò)誤捕獲?我想是不需要的。我們需要知道,錯(cuò)誤捕獲并不是無(wú)償?shù)?。在很多情況下我們并不需要去做這種特殊的處理,比如獲取分頁(yè)數(shù)據(jù)等。一般情況,只需要給一些可能會(huì)出現(xiàn)問(wèn)題的async/await做這個(gè)處理即可。
總結(jié)
捕獲async和await的方法有兩種
- 手動(dòng)添加try{}catch{}
- 使用await-to-js異步錯(cuò)誤處理庫(kù)
到此這篇關(guān)于await/async無(wú)法捕獲與處理錯(cuò)誤信息的解決方案的文章就介紹到這了,更多相關(guān)await/async無(wú)法捕獲與處理錯(cuò)誤內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js超時(shí)調(diào)用setTimeout和間歇調(diào)用setInterval實(shí)例分析
這篇文章主要介紹了js超時(shí)調(diào)用setTimeout和間歇調(diào)用setInterval,以實(shí)例形式對(duì)比分析了setTimeout與setInterval的具體使用技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-01-01
input file上傳 圖片預(yù)覽功能實(shí)例代碼
input file上傳圖片預(yù)覽其實(shí)很簡(jiǎn)單。今天小編就通過(guò)本文給大家介紹input file上傳 圖片預(yù)覽功能的實(shí)現(xiàn)代碼,比較簡(jiǎn)單,對(duì)input file 上傳預(yù)覽功能感興趣的朋友參考下吧2016-10-10
JavaScript簡(jiǎn)單獲取系統(tǒng)當(dāng)前時(shí)間完整示例
這篇文章主要介紹了JavaScript簡(jiǎn)單獲取系統(tǒng)當(dāng)前時(shí)間的方法,涉及javascript針對(duì)日期與時(shí)間的判斷以及字符串組合的相關(guān)技巧,需要的朋友可以參考下2016-08-08
超鏈接怎么正確調(diào)用javascript函數(shù)
本文介紹使用超鏈接調(diào)用javasript函數(shù)且不會(huì)影響GIF圖片動(dòng)畫的方法,有遇到相同問(wèn)題的小伙伴可以參考一下。2016-05-05
JavaScript判斷是否為數(shù)字的幾種方式匯總(推薦!)
有時(shí)候需要根據(jù)輸入的內(nèi)容來(lái)進(jìn)行計(jì)算,這個(gè)時(shí)候就需要判斷輸入的內(nèi)容是否是數(shù)字,下面這篇文章主要給大家介紹了關(guān)于JavaScript判斷是否為數(shù)字的幾種方式,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
JS識(shí)別瀏覽器類型(電腦瀏覽器和手機(jī)瀏覽器)
本文給大家分享一段js代碼關(guān)于識(shí)別瀏覽器的類型是手機(jī)瀏覽器還是電腦瀏覽器,有需要的朋友可以參考下本文2016-11-11
使用Browserify來(lái)實(shí)現(xiàn)CommonJS的瀏覽器加載方法
下面小編就為大家?guī)?lái)一篇使用Browserify來(lái)實(shí)現(xiàn)CommonJS的瀏覽器加載方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05

