Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

express.js request/response object life cycle when using callbacks

Please feel free to sort me out if this is a redundant question. (I have searched as much as I can bear before asking)

I am desperately trying to understand the life cycle of the request/response objects.

Consider the following skeleton code:

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.
}

(Please note that the original code does a whole lot more, such as checking if 'Cookie' even exists etc.)

I uderstand that req and res objects are created and must be at some point garbage collected. (One would hope)

When findCookieInDatabase() is called with setCookie as a parameter I'm assuming that setCookie is just a string (containing the function) at the time and does not get parsed nor executed until the callback(setCookie) statement is encountered in findCookieInDatabase().

I also understand that I might be utterly wrong with the above assumption which would be due to my lack of understanding the guts of javascript callbacks. (I have searched a lot on this also but all I could find is endless tuts on how to use callbacks. Nothing on what's under the hood)

So the question is this: How does javascript (or node.js) know how long to keep 'res' alive and when is it ok to garbage collect it?

Does the line res.sendfile in setCookie actually act as an active reference because it is invoked through findCookieInDatabase()?

Does javascript actually keep track of all the references and keeps req and/or res alive so long as any part of any called/callback-ed/things are alive?

Any help greatly appreciated. Thanks for reading.

like image 719
particle xlr8r Avatar asked Jun 25 '14 00:06

particle xlr8r


People also ask

How do I get response time in Express?

We can get the response time in the response header of a request with the response-time package. It has a responseTime function which returns a middleware that we can use with the use method of express or express. Router() .

What is the use of express JS response object?

The Response object (res) specifies the HTTP response which is sent by an Express app when it gets an HTTP request.

Which method sends response data in Express?

send() function basically sends the HTTP response. The body parameter can be a String or a Buffer object or an object or an Array. Parameter: This function accepts a single parameter body that describe the body which is to be sent in the response.

Which function tells what to do when a GET request at the given route is called?

app. get() is a function that tells the server what to do when a get request at the given route is called. It has a callback function (req, res) that listen to the incoming request req object and respond accordingly using res response object.


1 Answers

There's a lot going on with your code -- and your assumptions -- that indicates to me that you should study some JavaScript fundamentals. I would recommend the following books:

  • Speaking JavaScript, by Axel Rauschmayer
  • JavaScript: The Good Parts, by Douglas Crockford (please note: I don't think everything that Douglas Crockford says is golden, but I would consider this book required reading for aspiring JavaScript programmers)
  • Learning Node, by Shelley Powers

And of course my own book, Web Development with Node and Express. Okay, now that I've got all the reading material out of the way, let me try to get to the heart of your question.

When Node receives an HTTP request, it creates the req and res objects (which begin their life as instances of http.IncomingMessage and http.ServerResponse respectively). The intended purpose of those objects is that they live as long as the HTTP request does. That is, the client makes an HTTP request, the req and res objects are created, a bunch of stuff happens, and finally a method on res is invoked that sends an HTTP response back to the client, and at that point the objects are no longer needed.

Because of Node's asynchronous nature, there could be multiple req and res objects at any given time, distinguished only by the scope in which they live. This may sound confusing, but in practice, you never have to worry about that: when you write your code, you write it as if you were always ever dealing with one HTTP request, and your framework (Express, for example), manages multiple requests.

JavaScript does indeed have a garbage collector, which eventually deallocates objects after their reference count drops to zero. So for any given request, as long as there's a reference to the req object (for example), that object will not be deallocated. Here's a simple example of an Express program that always saves every request (this is a terrible idea, by the way):

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

The reason this is a terrible idea is that if you never remove objects from allRequests, your server will eventually run out of memory as it processes traffic.

Typically, with Express, you'll rely on asynchronous functions that invoke a callback once they've done their work. If the callback function has a reference to the req or res objects, they will not be deallocated until the asynchronous function completes and the callback executes (and all other references are out of scope, naturally). Here's a simple example that just generates an artificial delay:

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

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

If you navigate to /slow, your browser will spin for 3 seconds. In another browser, if you access /fast a bunch of times, you'll find that it still works. That's because Express is creating a req and res object for each request, none of which interfere with each other. But the res object associated with the /slow request is not deallocated because the callback (which is holding a reference to that instance) hasn't executed.

At the end of the day, I feel like you're overthinking things. It's good to understand the fundamentals, certainly, but for the most part, reference counting and garbage collection in JavaScript is not something you have to think about or manage.

I hope this helps.

like image 55
Ethan Brown Avatar answered Oct 05 '22 09:10

Ethan Brown