用好js與nodejs中的try...catch


對異常的捕獲和處理是提高程序魯棒性的一個重要方式,即使在javascript/nodejs等看似“很難寫出bug”的弱類型語言里,異常捕獲處理仍至關重要,這主要是因為:

1.在一個代碼塊里,如果程序運行過程中自動、或主動(new Error/Exception)生成異常/錯誤后,若不主動去try...catch該異常,這個異常會逐層拋出,直至主程序,系統會按照框架默認方式處理該異常。

2.在逐層拋出異常的過程中,每層代碼塊異常點之后的程序不會再被執行,除非進行try...catch異常處理。

我們看幾個簡單的例子來驗證一下。

(() => {
  try{
    (()=>{
      nonExistentFunction();
      console.log('c');
    })();
    console.log( 'b' );
  }catch(e){
    console.log( e );
  }
})();
console.log( 'a' );

 打印結果:

即,打印了最外層的catch內的異常處理信息和主程序接下來的部分,根據1,2可知,如果匿名函數最外層沒有進行try...catch處理的話,a也不會被打印出來。

這意味着,即使是“很難寫出bug”的javascript也可能因為一個小小的異常導致整個程序歇菜!try...catch則是保證主干按流程執行完畢的關鍵實現。

 

容易被誤處理的異步異常

在nodejs等異步IO密集場景,經常用異步回調函數來處理IO操作結果——不管是正確的數據還是異常Error,但此時的try...catch怎么來寫?

const fs = require('fs');
try{
  fs.readFile( __dirname+'/15_fs1.js',(err,data) =>{
      if( err ){
        throw err;
      }else{
        console.log( data );
      }
  } );
}catch(err){
  console.log( 'an error occured!',err );
}

console.log( 'hhh' );

在文件不存在的情況下,按照try..catch的作用,我們認為應該在catch里捕捉到異常並執行異常處理語句,即打印“an error occured!XXX”;但實際結果呢?

即,異常最后並未被目前縮寫的catch所捕獲,而是最終被系統級捕獲並按照框架方式打印出了錯誤信息,這是為什么呢?主要是因為try...catch是代碼塊,是被同步解析的,當代碼執行到try后,開始讀文件操作,等待異步執行結果,但catch語句是緊接着try進行的,它並不會等待異步執行的結果,因此,當執行到catch的時候,回調里的throw error還沒執行呢,當然catch不到了,主程序繼續解析執行直到打印出'hhh'。隨后當異步會調離throw err的時候沒有catch可以捕獲的到,只能層層拋出到最外層,由框架來捕獲和執行。

理解上述內容后,就該想到問題的關鍵點是try...catch的執行ticker與回調函數ticker不同步的問題,解決的辦法也很簡單,同步try...catch與callback函數的時鍾—將try..catch放在callback里面。

正確的代碼示例:

const fs = require('fs');

fs.readFile( __dirname+'/15_fs1.js',(err,data) =>{
  try{
    if( err ){
      throw err;
    }else{
      console.log( data );
    }
  }catch(e){
    console.log( e );
  }
} );
console.log( 'hhh' );

打印結果:

19年要在使用新框架寫好業務邏輯的基礎上,提高自己輸出代碼的魯棒性,經常去分析、反思可能出現異常的模塊並進行forecast error的捕獲處理,進一步提高自己的代碼水平。

 ——學無止境,保持好奇。May stars guide your way.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM