每個
調用一個函數時,該函數被壓入的被稱爲調用堆棧功能的堆疊。當該函數返回一個值時,它會彈出堆棧。調用堆棧描述了你在程序中的位置以及你如何到達那裏。
同步碼
通過想象調用堆棧出這個計劃的過程。
function a() { return b() }
function b() { return c() }
function c() { throw new Error() }
a();
首先,調用a
,所以我們將它添加到堆棧中。
[ a ]
然後a
電話b
,所以我們添加到堆棧中了。
[ a, b ]
然後b
調用c
。
[ a, b, c ]
然後c
將引發錯誤。在這一點上,調試器可以告訴你,c
是拋出錯誤的函數,並且你最終在c
,通過a
然後b
。這適用於普通的同步代碼,如JSON.parse
。
異步代碼
函數返回後異步代碼繼續運行。例如:
function a() {
setTimeout(function() { console.log(2); }, 10000);
return 1;
}
如果你打電話a
,然後將它推入調用堆棧,然後返回1
和被彈出調用堆棧。約10秒後,2
將被打印到控制檯中。
如果超時做到了,會發生什麼?
function a() {
setTimeout(function() { throw new Error(); }, 10000);
return 1;
}
錯誤將被拋出,但調用堆棧將爲空。正如你可以想象的,這對開發者來說並不是很有用。
這也是一個問題,如果我們想要異步返回一個值。當異步事件發生時(超時,讀/寫,網絡等),函數已經返回。
取而代之,我們可以使用一種稱爲Continuation-Passing Style的形式,通常稱爲回調。除了調用我們的異步函數外,我們還傳遞函數(繼續),我們要求它在完成時運行。記住,這可以在函數返回一個值之後!
在Node.js的,這些回調一舉兩得:
錯誤
如果出現錯誤,而這樣做的異步工作方式,標準的做法是調用回調與錯誤作爲第一個參數。你會經常看到下面的代碼。
foo.doAsyncBar(function(err, baz) {
if(err) throw err;
// do something with baz
});
通過傳遞錯誤的回調而不是拋出它,我們能夠做出我們自己的決定如何最好地處理它。我們可以拋出它,如上所示,或者我們可以以更優雅的方式處理它。
返回
希望的功能將不會錯誤,在這種情況下,一般的做法是通過null
作爲第一個參數回調。這讓編寫處理代碼的開發人員知道該函數沒有錯誤,並且返回值位於下一個參數之一中。
有關Node.js錯誤處理的更深入的文章,請參閱Joyent的Production Practices document for Errors。
https://www.joyent.com/developers/node/design/errors –