贊助商連結

Nodejs exception handling

by undefined

例外處理(Error handling or exception handling) 永遠都是程式設計師的惡夢,我曾是(現在也是 XD)一個 java 程式設計師, java 內的 try catch 也是挺惱人的,即便 java 7 裡面有新的 muti try catch ,但是還是挺麻煩的。

轉到 nodejs 之後,發現 javascript 的 error handling 也不遑多讓,因為 nodejs 充斥了大量的 async ,所以處理起來格外辛苦,不過基本上來說,還是有一些準則可以來參考。

接著,讓我們話說重頭,從 sync code 開始來探討


先看以下的 code

這隻是典型的 sync call ,我們呼叫了 syncCall() 預期回傳一個字串,但是這個 function 可能會發生 error。

執行一下,果然出了 exception

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
onlinemad:~ > ~/20130715_error_handling > node syncCall_1.js


/20130715_error_handling/syncCall_1.js:2
throw new Error('sync exception');
^
Error: sync exception
at syncCall (/20130715_error_handling/syncCall_1.js:2:9)
at Object.<anonymous> (/20130715_error_handling/syncCall_1.js:6:1)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:901:3

設計這個 function 的人採用了 throw 把 error 丟出去給呼叫 syncCall() 的人處理,所以當使用 syncCall() 的時候必須注意 exception 的處理。


接著看下一個範例

在 sync 的狀況下,用 try catch 就可以把 error 給抓住,所以 code 增加 try catch 來捕捉 exception

執行一下,果不其然 exception 被抓住並印出

1
2
onlinemad:~ > ~/20130715_error_handling > node syncCall_2.js
catch sycn exception

以上是 sync code 對於 exception 的處理方式。


不過正如一開始所說的 nodejs 充斥了大量的 async call 所以在處理 async call 的 exception 方式就跟 sync call 有很大的不同

先看下面這段 code

這隻是典型的 async call ,我們呼叫了 asyncCall() 傳入一個 callback function ,asyncCall() 做完後會把字串透過 callback function 傳回來,但是這個 async function 也可能會發生 error。

於使我們用 try catch 來捕捉 exception 看看

1
2
3
4
5
6
7
8
9
10
11
12
onlinemad:~/20130715_error_handling > node asyncCall_1.js

/20130715_error_handling/asyncCall_1.js:3
throw new Error('async exception');
^
Error: async exception
at /20130715_error_handling/asyncCall_1.js:3:9
at process._tickCallback (node.js:415:13)
at Function.Module.runMain (module.js:499:11)
at startup (node.js:119:16)
at node.js:901:3

很遺憾,在 async 的狀況下,無法使用 try catch 的方式來捕捉 exception。


所以在 async 的狀況下我們就要將 exception 透過 callback function 傳給 caller 來處理。

接著,我們修改 code ,把 exception 傳回給 caller,所以 callback function 的第一個參數就是 exception,在 caller 這邊的就要檢查 err 的狀態,如果 not null 就表示出 exception 了。

執行一下,果然可以抓住 async exception

1
2
onlinemad:~/20130715_error_handling > node asyncCall_2.js
catch asycn exception


回想 asyncCall_1.js 這個範例 asyncCall()

做完後會把字串透過 callback function 傳回來

所以回傳的字串呢?

再合併 asyncCall_2.js 這個範例

把 exception 傳回給 caller,所以 callback function 的第一個參數就是 exception

所以 async call exception handling 最佳作法如下

當有 exception 發生時把 exception 放在 callback function 的第一個參數傳回給 caller,當一切正常時 callback function 的第一個參數就擺 null 第二個參數擺執行的結果,這樣一來就可以完美地處理 async call 所發生的 exception 。

執行一下,當沒有 exception 發生時,就會把字串傳回給 callback function;當發生 exception 時就可以抓住 exception。

1
2
3
4
onlinemad:~/20130715_error_handling > node asyncCall_3.js
catch asycn exception
onlinemad:~/20130715_error_handling > node asyncCall_3.js
asyncCall


除了傳 error 給 callback function 的方式之外,還可以用 EventEmitter trigger 特定的事件。

asyncCall_3.js 的範例修改如下

當有 exception 發生時 emit 一個 error 事件,接著再把 exception 傳回去;當一切正常時 emit 一個 success 事件,同時把字串傳回去。

接著在使用這個 class 的時候就必須使用 on 綁一個 function 上去,這樣 emit 的事件才有對應的 function 可以處理。

執行一下,基本上跟 asyncCall_3.js 的範例一樣。

1
2
3
4
onlinemad:~/20130715_error_handling > node asyncCall_catch_by_event.js
[Error: async exception]
onlinemad:~/20130715_error_handling > node asyncCall_catch_by_event.js
asyncCall


另外還有兩種方式可以 handle exception,分別是使用 domain 跟 catch uncaughtException

這個範例是使用 domain 來 handle exception

d.run 把可能會出 exception 的 function 包起來,所以

執行一下,不論是 sync 或是 async call 都可以被 domain 的 on error function 抓住並處理

1
2
3
onlinemad:~/20130715_error_handling > node asyncCall_catch_by_domain.js
catch sync exception
catch async exception

不過 domain 的機制並不是再取代 try catch 也不是去抓住 async 的 exception,之後會在針對 domain 這個 module 來作探討。

更多細節可以參考 Node.js 的 API: Domain Node.js v0.10.15 Manual & Documentation


最後一種方式就是 catch uncaughtException 在 process module 可以綁一個 uncaughtException 事件

這個範例是使用 uncaughtException 事件來 handle exception

執行一下,錯誤可以被 uncaughtException 的事件抓住並處理

1
2
onlinemad:~/20130715_error_handling > node asyncCall_catch_by_uncaughtException.js
catch async exception

不過不建議 uncaughtException 來處理 exception,因為官方有說

Note that uncaughtException is a very crude mechanism for exception handling and may be removed in the future.

所以寫出來只是讓大家看看而已...


語言能做的就是提供好的方式去抓 exception,但是抓到 exception 後要怎樣處理那就是 programmer 要決定的事情,是要停止執行還是繼續執行替代 function 這就不在語言的範圍了。

總結 Node.js 的 exception handling 以 syncCall_2.jsasyncCall_3.js 的方式去 handle exception 會是最好的方式。


ref


所有的範例都放在 github githut:onlinemad/blog-ianwu-tw-example 有興趣的朋友可以 clone 一份回家 :)


喜歡我們的文章可以按上面的 LIKE 給我們鼓勵喔!