2015-02-23 84 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活动的结果,而无需担心线程管理等问题。

相关问题