面試官:請用一句話描述 try catch 能捕獲到哪些 JS 異常

日常擼代碼的時候,try catch 用的太多了,特別是一些 」安全感" 低的人,基本是處處 try catch,生怕 JS 報錯,而後頁面整個掛掉了。前端

其實爲啥會安全感低呢,是由於界限模糊。web

因此,咱們要作一個 「安全感」 高的碼農[狗頭][狗頭][狗頭]面試


  • 面試官:麻煩用一句話描述 JS 異常是否能被 try catch 到?promise

  • 面試者:異步方法沒法捕捉到……安全

  • 面試官:不要背答案,麻煩用一句話描述 JS 異常是否能被 try catch 到!微信

  • 面試者:沉默 ing …………異步

  • 面試者:能捕捉到的異常,必須是線程執行已經進入 try catch 但 try catch 未執行完的時候拋出來的。編輯器

  • 面試官: 沉默 ing …………ui

  • 面試官:啥時候能夠來上班?url

  • 歡笑交談中,拿到 offer …………


咱們咱們來分析下這個一句話描述 try catch 的含義。

主要分爲三段:try catch 以前,之中,以後。

以前

代碼報錯的時候,線程執行未進入 try catch,那麼沒法捕捉異常。

好比語法異常(syntaxError),由於語法異常是在語法檢查階段就報錯了,線程執行還沒有進入 try catch 代碼塊,天然就沒法捕獲到異常。

例子 1:

try{
    a.
}catch(e){
    console.log("error",e);
}
// output
Uncaught SyntaxError: Unexpected token '}'
複製代碼

之中

代碼報錯的時候,線程執行處於 try catch 之中,則能捕捉到異常。

看以下例子:

  • 方法和執行都在 try 裏面,能捕捉到異常。
try{
    function d(){a.b;}
   d();
}catch(e){
    console.log("error",e);
}
// output
error ReferenceError: a is not defined
複製代碼
  • 方法定義在外部,執行方法在 try 裏面,能捕捉到異常
function d(){a.b;}
try{
   d();
}catch(e){
     console.log("error",e);
}
// output
error ReferenceError: a is not defined
複製代碼

上述報錯的時機,都是代碼執行進入了 try catch ,執行 d() 方法的時候,線程執行處在 try 裏面,因此能捕捉到。

以後

代碼報錯的時候,線程已經執行完 try catch,這種不能捕捉到異常。

例子:

try{
    setTimeout(()=>{
         console.log(a.b);  
    }, 100)
}catch(e){
    console.log('error',e);
}
console.log(111);
//output
111
Uncaught ReferenceError: a is not defined
複製代碼

setTimeout 裏面報錯,其實是 100ms 以後執行的代碼報錯,此時代碼塊 try catch 已經執行完成,111 都已經被執行了,故沒法捕捉異常。

例子:

try{
   function d(){a.b;}
}catch(e){
     console.log("error",e);
}
console.log(111);
d();
// output
111
Uncaught ReferenceError: a is not defined
複製代碼

方法定義在 try catch 代碼塊裏面,可是執行方法在 try catch 外,在執行 d 方法的時候報錯,此時 try catch 已經執行完成,111 都已經被執行了,故而沒法捕捉異常。

總結

能被 try catch 捕捉到的異常,必須是在報錯的時候,線程執行已經進入 try catch 代碼塊,且處在 try catch 裏面,這個時候才能被捕捉到。

若是是在以前,或者以後,都沒法捕捉異常。

敲黑板:不要死記硬背,啥能夠捕獲,啥不能捕獲!記住這一句話,永遠不會忘!

Promise 沒異常

相對於外部 try catch,Promise 沒有異常!

例子 6:

try{
    new Promise(function (resolve, reject{
        a.b;
    }).then(v=>{
        console.log(v);
    });
}catch(e){
    console.log('error',e);
}
// output
Uncaught (in promise) ReferenceError: a is not defined
複製代碼

看如上報錯,線程在執行 a.b 的時候,事實上屬於同步執行,try catch 並未執行完成,按理應該能捕捉到異常,這裏爲啥沒法捕捉呢?

事實上,Promise 的異常都是由 reject 和 Promise.prototype.catch 來捕獲,無論是同步仍是異步。

核心緣由是由於 Promise 在執行回調中都用 try catch 包裹起來了,其中全部的異常都被內部捕獲到了,並未往上拋異常。

以下來自 Promises/A+ 的實現 then/promise 源碼:

function getThen(obj{
  try {
    return obj.then;
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

function tryCallOne(fn, a{
  try {
    return fn(a);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}
function tryCallTwo(fn, a, b{
  try {
    fn(a, b);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}
複製代碼

能夠看到,這裏執行 then (Promise.prototype.then 回調), tryCallTwo (doResolve 回調), tryCallOne (handleResolved 回調) 方法都被 try catch了。

異常都被包裹起來了。因此異常都不會被外層的 try catch 捕捉,所以在外層的 try catch 看來,Promise 根本沒有異常,事實上也確實沒有「異常」,好比:

try{
    new Promise(function (resolve, reject{
        a.b;
    }).then(v=>{
        console.log(v);
    });
    console.log(111);
}catch(e){
    console.log('error',e);
}
console.log(222);
// output
111
222
Uncaught (in promise) ReferenceError: a is not defined
複製代碼

顯然,a.b 報錯以後的,111 和 222 都能正常運行,promise 的異常都已經被內部 catch 了,在外層的 try catch 看來就是沒有異常,線程繼續執行。

try catch 沒法捕捉 Promise 的異常,是由於 Promise 的異常沒有往上拋。

再看一例:

function a(){
    return new Promise((resolve, reject) =>{
        setTimeout(() => {
            reject(1);
        })
    })
}
try{
    await a();
}catch(e){
    console.log('error',e);
}
console.log(111);
//output
error 1
111
複製代碼

這個例子的異常被 catch 捕獲到了,那麼這裏的 Promise 爲啥能捕獲到異常呢?

咱們仍是看開始的「一句話總結」

報錯的時候( setTimeout 裏面的 reject ),線程執行已經進入 try catch 代碼塊,可是並未執行完成,這樣的話固然能夠捕獲到異常。await 將代碼執行停留在 try catch 代碼塊裏面的緣故。

敲黑板了: 不要用 try catch 包裹 Promise , Promise 很強大,不用擔憂異常會往上拋!咱們只須要給 Promise 增長 Promise#catch 就 OK 了

歡迎關注個人微信公衆號,一塊兒作靠譜前端!

follow-me
相關文章
相關標籤/搜索