1. try/catch
公司主營業(yè)務(wù):成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊有機(jī)會用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)推出屯留免費(fèi)做網(wǎng)站回饋大家。
try/catch基本上是大家最常和async/await一起使用的,基本上我們會用它去包圍大部分的異步方法。await關(guān)鍵字后面的promise一旦reject了,就會拋出一個異常錯誤。
run(); async function run() { try { await Promise.ject(new Error('Oops!')); } catch (err) { console.error(error.message); } }
try/catch同樣也可以處理同步的錯誤,比如下面:
async function run() { const v = null; try { await Promise.resolve('foo'); v.thisWillThrow; } catch (error) { // 會出現(xiàn)"TypeError: Cannot read property 'thisWillThrow' of null" console.error(error.message); } }
好像我們只要無腦把邏輯都放到try/catch里面就萬事大吉了嗎?不太準(zhǔn)確,下面的代碼卻會導(dǎo)致unhandled promise rejection。這個return關(guān)鍵字直接返回就錯誤卻不會被捕獲:
async function run() { try { // 直接返回Promise,而不是用await關(guān)鍵字 return Promise.reject(new Error('Oops!')); } catch (error) { console.error(error.message); } }
一種處理方式是使用return await來解決。
try catch捕獲不了回調(diào)函數(shù)。try catch 僅僅在單一執(zhí)行環(huán)境中奏效。是在回調(diào)中加入try catch 來捕獲錯誤。
setTimeout(funciton() { try { fn() } catch (e) { // handle error } })
這是奏效的。 不過try catch會在各個地方。 V8引擎是不鼓勵try catch在函數(shù)中的使用的。 之前把try catch移到頂層來捕獲調(diào)用棧的錯誤,但這個對異步代碼不會奏效。
2. Golang-style(then)
golang style即使用.then()的方法來將一個promise轉(zhuǎn)換為另一個處理完錯誤的reject promise??梢允褂妙愃苅f(err)來進(jìn)行檢查:
async function throwAnError() { throw new Error('Opps!'); } async function runAwait() { let err = await throwAnError(); if (err){ console.error(err.message); } }
這么寫會直接拋出異常,因為這個方法拋出了異常,但是該方法本身沒有用try/catch捕獲。很多時候,我們在使用第三方庫的時候可能會出現(xiàn)這種情況。
then()解決方法
async function runAwait() { let err = await throwAnError().then(() => null, err => err); if (err){ console.error(err.message); } }
then()的方式,就會等待promise狀態(tài)resolve或reject后然后執(zhí)行相應(yīng)的回調(diào),然后判斷err對象并處理,所以其實它相當(dāng)于被捕獲了。
同時返回錯誤和值
async function run() { let [err, res] = await throwAnError().then(v => [null, v], err => [err, null]); if (err){ console.error(err.message); } console.log(res) }
結(jié)果:這么做可以通過解構(gòu)返回一個數(shù)組,包含了結(jié)果和error對象。當(dāng)然如果是reject就會返回null和error對象;而如果resolved返回數(shù)組的第一個error對象就為null,第二個就是結(jié)果。
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):這種模式可以更簡潔地處理,同時可以不需要寫catch。
缺點(diǎn)1:這是非常重復(fù)性的,每次執(zhí)行異步操作都需要去判斷error對象。
缺點(diǎn)2:無法幫助處理run方法中的同步錯誤。
所以這種方式需要謹(jǐn)慎使用。
3. Catch捕獲
上面兩種模式都可以處理異步錯誤,但是對于錯誤處理,最好的情況是在異步邏輯的最后加上catch,這樣可以保證所有錯誤都被捕獲到。其實這也是一個原則,即統(tǒng)一處理錯誤,而不是單獨(dú)去處理每個錯誤。
async function run() { return Promise.reject(new Error('Oops!')); } run().catch(function handleError(err) { console.error(err.message); }).catch( err => { process.nextTick(() => { throw errl}); })
使用catch捕獲錯誤,如果handleError本身也有錯誤,就需要再catch一遍,但是為了避免回調(diào)地獄,如果該方法發(fā)生了錯誤就終止該進(jìn)程。
優(yōu)缺點(diǎn)
4 全局錯誤捕獲
4.1 瀏覽器全局錯誤捕獲
瀏覽器全局處理基本上就是依靠事件,因為瀏覽器是事件驅(qū)動的。一旦拋出錯誤,解釋器在執(zhí)行環(huán)境上下文中停止執(zhí)行并展開,此時會有一個onerror全局事件拋出:
window.addEventListener('error', function (e) { var error = e.error; console.log(error); })
全局錯誤處理器會捕獲任何在執(zhí)行環(huán)境中發(fā)生的錯誤,即便是不同的對象發(fā)生的錯誤事件,或者是各種類型的錯誤。這是全局集中處理錯誤的一種常見方式。
調(diào)用棧
調(diào)用棧在定位問題的時候十分重要,我們可以使用調(diào)用棧在處理器中處理特定的錯誤。
window.addEventListener('error', function (e) { var stack = e.error.stack; var message = e.error.toString(); if (stack) { message += '\n' + stack; } var xhr = new XMLHttpRequest(); xhr.open('POST', '/log', true); // Fire an Ajax request with error details xhr.send(message); });
通過日志可以看到,具體什么情況觸發(fā)了什么錯誤。在調(diào)試時調(diào)用堆棧也會非常有用。你 可以分析log,看到什么條件下觸發(fā)了錯誤。
注意:
如果跨域腳本是不會看到錯誤的。 在JS中,錯誤信息僅僅是允許在同一個域中。
個人想法
更多的時候,代碼拋出了異常,我們更關(guān)注的是在運(yùn)行時,某個變量的值是什么,是否這個變量的值導(dǎo)致了錯誤,所以打印出調(diào)用時的跟多的信息更重要。
4.2 Node.js全局錯誤捕獲
Node.js本身的異常處理要復(fù)雜得多,因為涉及到了進(jìn)程或線程拋出異常的問題。
基于Koa的全局錯誤處理
nodejs是error-first的異步處理機(jī)制,此處底層會調(diào)用net模塊的listen方法并在錯誤發(fā)生時執(zhí)行回調(diào)。
app.listen(app.config.listenPort, (err) => { if (err) throw err app.logger.info(`> Ready on http://localhost:${app.config.listenPort}`) })
路由錯誤處理
對于每個路由,它可能也會有不同的錯誤處理邏輯,這時路由進(jìn)來的請求就需要根據(jù)情況返回不同的異常碼和信息。
router.get('/loginAuth', async (ctx, next) => { try { const code = query.code const res = await requestToken(code) if (res.data.code !== 0) { ctx.app.logger.error(`request token error.Code is ${res.data.code} || response is: ${JSON.stringify(res.data.data)} || msg: ${res.data.message}`) ctx.body = { code: 10000, message: `request token by code error` } } else { ctx.body = res.data } } catch (err) { ctx.app.logger.error(`request api has exception ${ctx.request.url} || ${err.code} || ${err.message} || ${err.stack}`) ctx.body = { code: 500, message: `Error response` } } })
5. 總結(jié)
Reference
async-await-error-handling
nodejs-v12-lts
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。
分享標(biāo)題:淺談如何優(yōu)雅處理JavaScript異步錯誤
URL鏈接:http://bm7419.com/article6/gocgog.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、靜態(tài)網(wǎng)站、網(wǎng)站建設(shè)、手機(jī)網(wǎng)站建設(shè)、虛擬主機(jī)、品牌網(wǎng)站設(shè)計
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)