2015-02-23 86 views
1

使用它吐出了一些錯誤處理代碼,這樣的express-generator爲什麼這個node.js回調沒有立即運行?

app.use('/', routes); 
app.use('/users', users); 

// catch 404 and forward to error handler 
app.use(function(req, res, next) { 
    var err = new Error('Not Found'); 
    err.status = 404; 
    next(err); 
}); 

// error handlers 

// development error handler 
// will print stacktrace 
if (app.get('env') === 'development') { 
    app.use(function(err, req, res, next) { 
     res.status(err.status || 500); 
     res.render('error', { 
      message: err.message, 
      error: err 
     }); 
    }); 
} 

在這個例子中,如果(無論出於何種原因)我的路線被破壞或者路由未找到或什麼的,代碼回落在第二個代碼塊中拋出一個404。在第二個代碼塊(404處理程序)開始執行後,第三個代碼塊(500處理程序)如何不立即執行?

我認爲這樣的node.js回調的工作是函數開始執行,並繼續在後臺執行,那麼接下來的回調開始在同一時間執行。但顯然,我對同步回調的工作方式感到困惑。在運行500錯誤處理程序之前,上述代碼是否知道要「等待」404處理程序代碼完成執行?

回答

1

所有app.use()報表時,您的應用程序初始化運行。他們每個人都建立了一個「中間件」處理程序。他們當時並沒有真正運行處理程序,只是將它們註冊到Express中間件堆棧中。如果它們之前沒有處理程序處理頁面,那麼這兩個最後的app.use()中間件處理程序將順序發送請求,而第二個處理程序只有在第一個請求傳遞給更多處理程序時纔會看到請求。

404處理程序將狀態設置爲404,然後將調用中間件堆棧的next()處理程序。這將最後成爲你的最後一個app.use()聲明,該聲明將查看是否已經設置了狀態,如果沒有,將其設置爲500,但是如果它之前被設置爲404,則它將離開它。然後,它將應用缺省頁面的默認渲染,以顯示頁面中的狀態。

這是具有其中默認渲染應用於一個地方的一種手段,但多個地方,可以設置錯誤。

沒有一個與異步行爲有關。只有在next()被較早的請求處理程序調用時,列表中的下一個請求處理程序纔會啓動。沒有「等待」。您可以考慮使用最後app.use()語句就像一個同步函數調用404請求處理的時候調用next()它只是說請鏈執行下一個請求處理程序,現在(它碰巧知道的是,提供的默認渲染一個爲錯誤狀態代碼)。


查看app.use()在Express中的工作方式可能會有所幫助。

每次調用app.use()增加了一個請求處理程序列表。當一個給定的http請求進入時,Express從列表中的第一個請求處理程序開始,並檢查列表中第一個請求處理程序的參數是否與當前請求相匹配(例如,路徑匹配或設置的任何其他參數app.use()聲明)。如果匹配,則它調用該請求處理程序。如果該請求處理程序沒有調用next()來讓列表中的下一個請求處理程序有請求的機會,則完成所有處理,並且Express假定第一個請求處理程序已完全處理請求。如果這個第一個請求處理程序沒有完全處理請求(比如說它只是在頭中檢查一個cookie值並且想要繼續處理其他處理程序),那麼它將調用next()。這告訴express查看列表中的下一個app.use()處理程序,並查看它是否與此請求匹配。

只要沒有請求處理程序匹配當前請求,或者每個請求持續呼叫next()以保持鏈條繼續運行,Express將繼續在列表中尋找一些請求處理程序來處理請求並生成服務器響應。在您的具體示例中,鏈中的第二個請求是404處理程序。它假設,如果Express將這一點遠遠地放在鏈中,那麼沒有處理程序尚未處理此請求,因此它必須是該服務器不能處理的頁面請求。因此,它將狀態設置爲404.然後,因爲錯誤頁面的默認呈現位於最後一個請求處理程序中,所以它會調用next()以觸發最後一個帶有錯誤的默認頁面呈現。


+0

@Jakobud - 您是否獲得足夠的解釋來回答/解釋您的問題,還是仍然存在你需要幫助嗎? – jfriend00 2015-02-27 04:17:36

0

解釋器中只有一個線程正在運行您的代碼。 I/O操作是併發執行的,這樣JS執行就可以繼續而不會阻塞I/O。它被稱爲異步,因爲回調執行的時間和順序不在您的直接控制之下。兩個JavaScript函數不會同時執行。

上面的代碼將完全運行,不會執行的回調函數。在您的代碼運行後,http模塊將偵聽客戶端請求(通常,您沒有在上面顯示)。響應這些客戶請求,回調將根據需要執行。它們並不是一直在單獨的線程中運行並等待數據。 app.use只在express中間件堆棧中註冊函數。當請求與您指定的路由匹配(或不匹配)時,將按順序調用適用的回調。這就是爲什麼你必須在你的中間件中調用next;如果您不這樣做,則停止處理該請求對象(此設計稱爲continuation passing style)。

確切執行這些功能的順序不爲您所知,並不重要。只有相對的順序很重要,即首先調用兩個函數中的哪一個。通常,代碼結構將保證這一點(即爲I/O調用提供回調函數)。這意味着解釋器能夠立即處理每個I/O活動的結果,而無需擔心線程管理等問題。

相關問題