一文搞定JS異常捕獲

在這裏插入圖片描述

  關於JS的異常捕獲,主要分爲兩種,一種爲同步情況下的異常捕獲,一種爲一步執行下的異常捕獲;異常捕獲的【坑】主要集中在異步場景。

同步

  在同步場景下,簡單粗暴,直接使用try/catch解決問題。

(function() {
  try {
    // catch: ReferenceError: obj is not defined
    console.log(obj.error)
  } catch (e) {
    console.log('catch:', e)
  }
})();

catch: ReferenceError: obj is not defined
    at <anonymous>:4:17
    at <anonymous>:8:3

異步

setTimeout異常

在異步場景下,按照上面的異常捕獲方式是無法捕獲到異常的,如下

// 無法捕獲到異常
(function() {
  try {
    setTimeout(function() {
      console.log(obj.error)
    }, 500)
  } catch (e) {
    console.log('catch:', e)
  }
})()

Uncaught ReferenceError: obj is not defined
    at <anonymous>:4:19
    at i (init.js:1)

之所以無法捕獲到異常,原因在於異步方法執行時,主流程已執行完畢,try/catch已經退出函數調用棧;正確的異常捕獲如下:

(function() {
  try {
    setTimeout(function() {
      try {
        console.log(obj.error)
      } catch (e) {
        // 此處捕獲到異常
        console.log('catch1:', e)
      }
    }, 500)
  } catch (e) {
    // 此處無法捕獲到異常
    console.log('catch2:', e)
  }
})()

catch1: ReferenceError: obj is not defined
    at <anonymous>:5:21
    at i (init.js:1)

從這裏可以看出,最外層的try/catch是不生效的,可以去掉。

promise異常

首先通過兩端代碼來看promise的異常捕獲情況
代碼一:

(function() {
  try {
    const promise = new Promise((resolve, reject) => {
      setTimeout(function() {
        // 此處的異常無法被捕獲
        console.log('1', obj.error)
        resolve(100)
      })
    })
    promise.then(result => {
      console.log('result:', result)
    }).catch(error => {
      // 此處無法捕獲到異常
      console.log('catch1:', error)
    })
  } catch (e) {
    // 此處無法捕獲到異常
    console.log('catch2:', e)
  }
})();

Uncaught ReferenceError: obj is not defined
    at <anonymous>:6:26
    at i (init.js:1)

代碼二:

(function() {
  try {
    const promise = new Promise((resolve, reject) => {
      console.log(obj.error)
      setTimeout(function() {
        resolve(100)
      })
    })
    promise.then(result => {
      console.log('result:', result)
    }).catch(error => {
      // 此處捕獲到異常
      console.log('catch1:', error)
    })
  } catch (e) {
    // 此處無法捕獲到異常
    console.log('catch2:', e)
  }
})()

catch1: ReferenceError: obj is not defined
    at <anonymous>:4:19
    at new Promise (<anonymous>)
    at <anonymous>:3:21
    at <anonymous>:19:3

總結:

  1. 最外層的try/catch對於promise中的異常捕獲完全無效
  2. new Promise()中的異步異常(setTimeout)只能在內部捕獲
  3. new Promise()中的同步異常只能通過catch捕獲

核心:熟悉EventLoop就知道,每個任務使用獨立的函數調用棧;所以,每一個task都需要單獨捕獲異常;使用promise.catch能夠捕獲到promise任務的異常。

async/await異常

追尋talk is cheap,show me the code的原則,這裏直接上驗證代碼,讓實際結果來說明一切。

function f() {
  return new Promise((resolve, reject) => {
    console.log(obj.error)
    setTimeout(function() {
      // 1.這裏的異常只能在setTimeout內部使用try/catch捕獲
      // console.log(obj.error)
      resolve(100)
    })
  })
}
async function main() {
  try {
    const result = await f().catch(e => {
      // 2.優先捕獲到異常
      console.log('catch1:', e)
    })
    console.log(result)
  } catch (e) {
    // 3.如果沒有catch1,這裏也能捕獲到異常
    console.log('catch2:', e)
  }
}
main()

總結:

  1. new Promise()中的異步異常(setTimeout)只能在內部捕獲
  2. 可以使用.catch也可使用try/catch來捕獲異常,其中.catch優先級較高

作者公衆號:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章