亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

淺談如何優雅處理JavaScript異步錯誤

發布時間:2020-09-03 15:02:17 來源:腳本之家 閱讀:224 作者:XXXSpade 欄目:web開發

1. try/catch

try/catch基本上是大家最常和async/await一起使用的,基本上我們會用它去包圍大部分的異步方法。await關鍵字后面的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) {
    // 會出現"TypeError: Cannot read property 'thisWillThrow' of null"
   console.error(error.message);
 }
}

好像我們只要無腦把邏輯都放到try/catch里面就萬事大吉了嗎?不太準確,下面的代碼卻會導致unhandled promise rejection。這個return關鍵字直接返回就錯誤卻不會被捕獲:

async function run() {
  try {
    // 直接返回Promise,而不是用await關鍵字
    return Promise.reject(new Error('Oops!'));
  } catch (error) {
    console.error(error.message);    
  }
}

一種處理方式是使用return await來解決。

try catch捕獲不了回調函數。try catch 僅僅在單一執行環境中奏效。是在回調中加入try catch 來捕獲錯誤。

setTimeout(funciton() {
 try {
  fn()
 } catch (e) {
   // handle error
 }     
      
})

這是奏效的。 不過try catch會在各個地方。 V8引擎是不鼓勵try catch在函數中的使用的。 之前把try catch移到頂層來捕獲調用棧的錯誤,但這個對異步代碼不會奏效。

2. Golang-style(then)

golang style即使用.then()的方法來將一個promise轉換為另一個處理完錯誤的reject promise。可以使用類似if(err)來進行檢查:

async function throwAnError() {
  throw new Error('Opps!');
}

async function runAwait() {
  let err = await throwAnError();
  if (err){
    console.error(err.message);
  }
}

這么寫會直接拋出異常,因為這個方法拋出了異常,但是該方法本身沒有用try/catch捕獲。很多時候,我們在使用第三方庫的時候可能會出現這種情況。

then()解決方法

async function runAwait() {
    let err = await throwAnError().then(() => null, err => err);
  if (err){
    console.error(err.message);
  }
}

then()的方式,就會等待promise狀態resolve或reject后然后執行相應的回調,然后判斷err對象并處理,所以其實它相當于被捕獲了。

同時返回錯誤和值

async function run() {
  let [err, res] = await throwAnError().then(v => [null, v], err => [err, null]);
  if (err){
    console.error(err.message);
  }
  console.log(res)
}

結果:這么做可以通過解構返回一個數組,包含了結果和error對象。當然如果是reject就會返回null和error對象;而如果resolved返回數組的第一個error對象就為null,第二個就是結果。

優缺點

優點:這種模式可以更簡潔地處理,同時可以不需要寫catch。
缺點1:這是非常重復性的,每次執行異步操作都需要去判斷error對象。
缺點2:無法幫助處理run方法中的同步錯誤。

所以這種方式需要謹慎使用。

3. Catch捕獲

上面兩種模式都可以處理異步錯誤,但是對于錯誤處理,最好的情況是在異步邏輯的最后加上catch,這樣可以保證所有錯誤都被捕獲到。其實這也是一個原則,即統一處理錯誤,而不是單獨去處理每個錯誤

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一遍,但是為了避免回調地獄,如果該方法發生了錯誤就終止該進程。

優缺點

  • 使用catch的話,不管異步方法本身是否捕獲錯誤,它都會去捕獲異步錯誤。
  • 使用try/catch無法避免catch本身拋出異常,而如果它拋出了那除了嵌套多一層try/catch外,最好的做法就是加catch來讓代碼更簡潔。

4  全局錯誤捕獲

4.1 瀏覽器全局錯誤捕獲

瀏覽器全局處理基本上就是依靠事件,因為瀏覽器是事件驅動的。一旦拋出錯誤,解釋器在執行環境上下文中停止執行并展開,此時會有一個onerror全局事件拋出:

window.addEventListener('error', function (e) {
  var error = e.error;
  console.log(error);
})

全局錯誤處理器會捕獲任何在執行環境中發生的錯誤,即便是不同的對象發生的錯誤事件,或者是各種類型的錯誤。這是全局集中處理錯誤的一種常見方式。

調用棧

調用棧在定位問題的時候十分重要,我們可以使用調用棧在處理器中處理特定的錯誤。

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);
});

通過日志可以看到,具體什么情況觸發了什么錯誤。在調試時調用堆棧也會非常有用。你 可以分析log,看到什么條件下觸發了錯誤。

淺談如何優雅處理JavaScript異步錯誤

注意:

如果跨域腳本是不會看到錯誤的。 在JS中,錯誤信息僅僅是允許在同一個域中。

個人想法

更多的時候,代碼拋出了異常,我們更關注的是在運行時,某個變量的值是什么,是否這個變量的值導致了錯誤,所以打印出調用時的跟多的信息更重要。

4.2 Node.js全局錯誤捕獲

Node.js本身的異常處理要復雜得多,因為涉及到了進程或線程拋出異常的問題。

基于Koa的全局錯誤處理

nodejs是error-first的異步處理機制,此處底層會調用net模塊的listen方法并在錯誤發生時執行回調。

app.listen(app.config.listenPort, (err) => {
 if (err) throw err
 app.logger.info(`> Ready on http://localhost:${app.config.listenPort}`)
})

路由錯誤處理

對于每個路由,它可能也會有不同的錯誤處理邏輯,這時路由進來的請求就需要根據情況返回不同的異常碼和信息。

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. 總結

  1. 通常異常可能是預期的或者超出預期的,不管怎樣,使用try/catch沒有問題。
  2. 對于超出預期的錯誤,盡量使用catch來保證它們會被捕獲到。
  3. 把錯誤處理器添加到window對象上,它會捕獲到異步錯誤,符合了DRY和SOLID原則。一個全局的錯誤處理器可以幫你保持異步代碼整潔。

Reference

async-await-error-handling
nodejs-v12-lts

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

明光市| 文安县| 九龙县| 廊坊市| 珲春市| 都安| 南华县| 湾仔区| 元阳县| 布拖县| 和政县| 盐边县| 常宁市| 扶余县| 文安县| 岑溪市| 阿瓦提县| 金川县| 酒泉市| 融水| 建宁县| 苍梧县| 巴彦淖尔市| 谢通门县| 永泰县| 衡阳市| 蕲春县| 曲松县| 通海县| 贵阳市| 五莲县| 津市市| 福州市| 诸暨市| 桦甸市| 翁牛特旗| 巴彦淖尔市| 焦作市| 杭锦后旗| 隆林| 社旗县|