express.js使用回调时的请求/响应对象生命周期

时间:2014-06-25 00:07:43

标签: javascript express callback garbage-collection lifecycle

如果这是一个多余的问题,请随时解答我。 (在问之前我已经尽可能多地搜索了)

我拼命想要了解请求/响应对象的生命周期。

考虑以下框架代码:

app.get('/', function(req, res) {

  var setCookie = function(err, idCookie) { //callback after cookieSearch in DB
    // ... do something with the result of findCookieInDatabase() (handle error, etc.);
    res.sendfile('index.html');
  }

  var cookie = parseCookie(req.get('Cookie')); //parse and format cookie

  findCookieInDatabase(cookie, afterCookieSearch); //tries to find cookie is DB


  // .. do some content return stuff, etc.
}

(请注意,原始代码会更多,例如检查Cookie是否存在等等。)

我理解创建了req和res对象,并且必须在某些时候收集垃圾。 (人们希望)

当使用setCookie作为参数调用findCookieInDatabase()时,我假设setCookie当时只是一个字符串(包含函数),并且在遇到回调(setCookie)语句之前不会被解析或执行在findCookieInDatabase()中。

我也理解我可能完全错误的上述假设,这可能是由于我对javascript回调的缺乏了解。 (我已经在这方面进行了很多搜索,但是我能找到的却是关于如何使用回调的无穷无尽的东西。没有什么关于引擎盖下的内容)

所以问题是: javascript(或node.js)如何知道保持多久' res'还活着什么时候垃圾收集它可以吗?

setCookie中的res.sendfile行实际上是否作为活动引用,因为它是通过findCookieInDatabase()调用的?

javascript是否实际上跟踪所有引用并保持req和/或res,只要任何被调用/回调/事物的任何部分都存活?

任何帮助非常感谢。谢谢你的阅读。

1 个答案:

答案 0 :(得分:13)

你的代码还有很多 - 以及你的假设 - 这表明你应该学习一些JavaScript基础知识。我会推荐以下书籍:

当然是我自己的书,Web Development with Node and Express。好的,既然我已经把所有阅读材料都拿走了,那么让我试着深入探讨你的问题。

当Node收到HTTP请求时,它会创建reqres个对象(分别以http.IncomingMessagehttp.ServerResponse的实例开始生效。这些对象的预期用途就是它们只要HTTP请求就存在。也就是说,客户端发出HTTP请求,创建reqres个对象,发生一堆事情,最后调用res上的方法,发送HTTP响应到客户端,此时不再需要这些对象。

由于Node的异步性质,在任何给定时间可能有多个reqres个对象,仅区别于它们所处的范围。这可能听起来令人困惑,但在实践中,您永远不必担心:当您编写代码时,您将其编写为就像您始终处理一个HTTP请求一样,并且您的框架(例如,Express)管理多个请求。

JavaScript确实有一个垃圾收集器,它最终会在引用计数降为零后释放对象。因此,对于任何给定的请求,只要有req对象的引用(例如),该对象就不会被释放。这是一个Express程序的简单示例,它始终保存每个请求(顺便说一下,这是一个糟糕的主意):

var allRequests = [];
app.use(function(req, res, next) {
    allRequests.push(req);
    next();
});

这是一个可怕的想法的原因是,如果你永远不会从allRequests中删除对象,那么你的服务器在处理流量时最终会耗尽内存。

通常,使用Express,您将依赖异步函数,这些函数在完成工作后调用回调。如果回调函数具有对reqres对象的引用,则在异步函数完成并且回调执行(并且所有其他引用自然超出范围)之前,它们将不会被释放。这是一个简单的例子,它只会产生一个人工延迟:

app.get('/fast', function(req, res) {
    res.send('fast!');
});

app.get('/slow', function(req, res) {
    setTimeout(function() {
        res.send('sloooooow');
    }, 3000);
});

如果您导航到/slow,您的浏览器将旋转3秒钟。在另一个浏览器中,如果您多次访问/fast,您会发现它仍然有效。这是因为Express正在为每个请求创建一个reqres对象,其中没有一个会相互干扰。但是,与res请求关联的/slow对象未被释放,因为回调(持有对该实例的引用)尚未执行。

在一天结束的时候,我觉得你想要过度思考。当然,理解基础知识是件好事,但在大多数情况下,JavaScript中的引用计数和垃圾收集不是你必须考虑或管理的事情。

我希望这会有所帮助。