trycatch 不能捕獲執行時異常_面試官:用一句話描述 JS 異常是否能被 try catch 捕獲到 ?...

語言: CN / TW / HK

theme: juejin highlight: darcula


關於寫這篇部落格的原因,是因為最近在工作中用try,catch捕獲Promise錯誤時,有的時候捕獲不到,有的時候又被promise.catch捕獲,對其捕獲機制和順序並不是很明白,查閱了很多資料,也沒有寫的很透徹的資料,所以寫篇部落格,方便日後查閱

前言

平常擼程式碼的時候,try catch 用的太多了,特別是一些 ”安全感" 低的人,基本是到處 try catch,生怕 JS 報錯,然後頁面整個掛掉了。

為什麼安全感低呢,因為界限模糊,很多新手前端不知道try,catch捕獲的是哪種異常,而且能否捕獲Promise異常,以及如果Promise用.catch捕獲,到底被誰捕獲到

所以我們要弄清楚try catch,做一個安全感高的碼農!!!

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

  • 面試者:非同步方法無法捕捉到……

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

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

  • 面試者:能捕捉到的異常必須是執行緒執行已經進入 try catch 但 try catch 未執行完的時候丟擲來的。

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

  • 面試官:啥時候可以來上班?

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

u=289018151,172936710&fm=26&fmt=auto.webp

關於trycatch的執行機制

當程式執行到try catch裡面時,如果未報錯,則忽略catch中的程式碼,若報錯,則不執行try報錯內容後面的程式碼,轉而執行catch中的程式碼。

什麼時候try catch 才能捕獲到異常?

能捕捉到的異常必須是執行緒執行已經進入 try catch 但 try catch 未執行完的時候丟擲來的

1,當語法錯誤時,不能捕獲

因為語法錯誤是在語法檢查階段就報錯了,執行緒執行尚未進入 try catch 程式碼塊,自然就無法捕獲到異常。 例如: try{ a. }catch(e){ console.log("error",e); } // output Uncaught SyntaxError: Unexpected token '}'

image.png

2,語法正確,執行緒進入try catch中時,可以捕獲

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

image.png 程式碼執行進入了 try catch ,執行 d() 方法的時候,執行緒執行處在 try 裡面,所以能捕捉到。

3,非同步無法捕獲

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

因為,setTimeout是非同步函式,而try catch其實是同步順序執行的程式碼,等setTimeout裡面的事件進入事件佇列的時候,主執行緒已經離開了try catch,所以try catch是無法捕獲非同步函式的錯誤的。

4.Promise異常無法捕獲

// 非同步,微任務 try { new Promise(() => { throw new Error('new promise throw error'); }); } catch (error) { console.log(error); } image.png try-catch 主要用於捕獲異常,注意,這裡的異常,是指同步函式的異常,如果 try 裡面的非同步方法出現了異常,此時catch 是無法捕獲到異常的,原因是因為:當非同步函式丟擲異常時,對於巨集任務而言,執行函式時已經將該函式推入棧,此時並不在 try-catch 所在的棧,所以 try-catch 並不能捕獲到錯誤。對於微任務而言,比如 promise,promise 的建構函式的異常只能被自帶的 reject 也就是.catch 函式捕獲到。

如果想要捕獲Promise異常

  • 1.Promise異常並不是絕對不能被捕獲到的,如下 async function fn() { try { await new Promise(() => { throw new Error('new promise throw error'); }); } catch (error) { console.log(error); } } fn() 程式碼執行結果

image.png

這次Promise異常能被捕獲到,是因為async和await,正常不加async,await的時候,執行promise後,在等待promise回撥的時候,try,catch已經執行完了,所以捕獲不到,然而加了async和await後,try,catch必須等promise的回撥執行完後,才能繼續往下走,這個時候trycatch沒執行完,promise丟擲異常,自然而然能被catch捕獲到

  • 2.關於promise異常到底是被catch捕獲還是.catch捕獲 接下來我們把程式碼修改一下 async function fn() { try { await new Promise(() => { throw new Error('new promise throw error'); }).catch(error=>{ console.log('.catch',error); }) } catch (error) { console.log('try,catch',error); } } fn() .catch大家都知道,用來捕獲promise異常,當我們有了.catch,錯誤在進入catch之前,就被.catch捕獲到了,所以不會再往下走(可能有點繞,.catch是Promise異常捕獲機制,不帶. 是try,catch) 程式碼執行結果如下

image.png 到這裡,我們可以發現,這個錯誤被.catch捕獲到了,那如果我們不丟擲一個錯誤,直接返回一個reject 會怎麼樣呢 async function fn() { try { const res = await new Promise((resove,reject) => { return reject('捕獲到了') }).catch(error=>{ console.log('被promise.catch',error); }) } catch (error) { console.log('被try,catch',error); } } fn() 執行結果

image.png

Promise異常,如果寫了.catch,就會被優先.catch捕獲到,如果沒有,那麼就會被try,catch捕獲到,

總結

通過上面分析,我們得出能被 try catch 捕捉到的異常,必須是在報錯的時候,執行緒執行已經進入 try catch 程式碼塊,且處在 try catch 裡面,這個時候才能被捕捉到。 並且,try,catch如果使用async和await,也是可以捕獲到Promise異常的,但我們不推薦,畢竟,Promise異常有它自己的.catch來捕獲,而且更好用,不是嗎?

所以,沒安全感的兄弟們,看完這篇文章,不要再到處寫trycatch了,我們自己寫的程式碼,沒我們想的這麼脆弱

如果上述文章有哪裡不對或需要改進,可以再底下評論或私信,一起學習交流

編輯不易,個位看官老爺,點個讚唄!!!!!!

參考文獻 - https://blog.csdn.net/weixin_39850143/article/details/111346809 - https://blog.csdn.net/xiaoluodecai/article/details/107297404