110

I'm wondering what the mechanics behind the behaviour of the following code are:

res.send(200, { data: 'test data' });
console.log('still here...');

My understanding is that res.send doesn't return the function, but does close the connection / end the request. This could explain why I can still execute code after a res.send command (I looked through the express source and it doesn't seem to be an asynchronous function).

Is there something else at play that I may be missing?

Renato Gama
  • 16,431
  • 12
  • 58
  • 92
Leonidas
  • 2,110
  • 4
  • 20
  • 31
  • sorry, I misread your post and wasn't sure what the issue was with your code since it is perfectly legit. when you call `send` it just pipes data out the http connection and your code continues. you can just use `return` if you want to terminate the code, or just not write anything else. sorry for misinterpretation. – Timmerz Apr 23 '13 at 23:17

3 Answers3

161

Sure end ends the HTTP response, but it doesn't do anything special to your code.

You can continue doing other things even after you've ended a response.

What you can't do, however, is do anything useful with res. Since the response is over, you can't write more data to it.

res.send(...);
res.write('more stuff'); // throws an error since res is now closed

This behavior is unlike other traditional frameworks (PHP, ASP, etc) which allocate a thread to a HTTP request and terminate the thread when the response is over. If you call an equivalent function like ASP's Response.End, the thread terminates and your code stops running. In node, there is no thread to stop. req and res won't fire any more events, but the code in your callbacks is free to continue running (so long as it does not attempt to call methods on res that require a valid response to be open).

Flame_Phoenix
  • 16,489
  • 37
  • 131
  • 266
josh3736
  • 139,160
  • 33
  • 216
  • 263
  • Ah ok, so the reason that we can continue code after the request is sent is because there is no thread in node to stop? So the browser, the response is sent, connection is closed, but that doesn't mean the script has exited. I've leveraged this behaviour before but just wasn't sure about the WHY behind it. – Leonidas Apr 24 '13 at 01:10
  • Any ideas on how to return the function after send? – OscarVGG Nov 03 '13 at 18:21
  • i mean stop execution, break the function. – OscarVGG Nov 05 '13 at 21:35
  • @OscarVGG: No, there is nothing to stop (short of exiting the process). – josh3736 Nov 05 '13 at 22:47
  • In other words, node.js is unlike php where application context = request context. – redben Dec 07 '13 at 10:38
  • the answer I was looking for was `return callback();`. I think this is called "short-circuiting". Sorry if i could not ask it the right way – OscarVGG Dec 11 '13 at 02:06
  • @OscarVGG: That's not really short-circuiting, which has a [well-defined meaning](http://en.wikipedia.org/wiki/Short-circuit_evaluation). That's just invoking the callback and returning. – josh3736 Dec 11 '13 at 02:52
  • 14
    this answer was very helpful and has convinced me to leave nodejs for ideological reasons. – jkatzer Apr 15 '14 at 03:16
  • 43
    @jkatzer ideology is weak. pragmatism wins. – Anatoly G Apr 15 '14 at 03:22
  • @ i agreed with that,but how can i stop execution of code after res.end – Prabjot Singh Apr 03 '15 at 06:53
  • @PrabjotSingh just always write `return res.send(...);` or `return res.end();` – NathanW Jul 07 '15 at 03:28
  • 1
    That doesn't really guarantee anything -- async callbacks in scope can still run. – josh3736 Jul 07 '15 at 05:37
  • 11
    Of course, try to remember that Node is just an execution environment, if you are using expressjs, this is your web server. What you are saying is like wondering why Apache keeps running after php returns a response. You can either choose to use this extra capacity, maybe you want to log the state of the response after it is sent, or do some other application functions, its up to you. However, with great power, comes great responsibility... – samazi Aug 25 '16 at 01:41
  • 2
    @AnatolyG I read your comment at least 5 times while reading this comment section and I read it plagiarism everytime and was laughing on it, now on myself. Lol. – Lalit Fauzdar May 10 '20 at 15:40
54

Edit: I no longer do what is explained below, as you shouldn't return a value when there is no need for it. It makes your code less readable and looks hackish. Instead, I suggest separating the return statement from the res.send(). @slavafomin explained this well in the comments.

A simple way to stop the execution of the function and send a response at the same time is by doing

return res.send('500', 'Error message here');

This allows you to use short if statements to handle errors such as:

if (err) {
    return res.send('500', 'Error message here');
}

The exact return of the res.send function is an object that seems to contain the entire state of the connection after you ended it (request, status, headers, etc.), but this should be unimportant since you won't be doing anything with it.

Marcos Pereira
  • 1,169
  • 14
  • 23
  • 3
    This is a great point, but not technically the answer,. since the question is more about the why than the how. Great contribution nonetheless, hence the upvote :). – Nepoxx Dec 10 '14 at 17:20
  • 3
    Yea, at the time I couldn't comment however, so I had to post an answer. – Marcos Pereira Dec 10 '14 at 19:16
  • 4
    I would recommend against using this technique. It makes code shorter, but it also makes it less meaningful and vague, cause it uses incorrect semantics. If you are not using the value from the function, then you shouldn't return one. Also it could break typed JavaScript (like TypeScript) and tools using static code analysis. In other words: it looks hackish and unprofessional. – Slava Fomin II May 30 '17 at 22:39
  • 1
    @SlavaFominII It can be like this: `res.send('500', 'Error message here');return;` inside `if` statement. – Ali Sherafat Jul 21 '17 at 17:53
  • @SlavaFominll I think this method is so common you can't call it hackish anymore. As for static analyzers - since express developers are the ones handling returns from this function, I'm pretty sure there is not much to worry about. Did you encounter a specific problem? – Ohad Cohen Nov 04 '20 at 05:10
  • 2
    If you are concerned about returning unused values, you can use the `void` keyword: `return void res.send('500', 'Error message here');`. This will ensure that `undefined` is returned from the function. – ut9081 Jul 29 '21 at 07:45
0

A possible solution is with this library: on-finished

var destroy = require('destroy')
var fs = require('fs')
var http = require('http')
var onFinished = require('on-finished')

http.createServer(function onRequest (req, res) {
  var stream = fs.createReadStream('package.json')
  stream.pipe(res)
  onFinished(res, () => {
    destroy(stream)
  })
})

Works with Express too, for example:

const express = require('express');
const app = express();

app.get('/video', (req, res) => {
 const ffmpeg = spawn(ffmpegPath, argsArray);
 ffmpeg.stdout.pipe(res);
 onFinished(res, () => {
   ffmpeg.kill();
 });
});
Boris Yakubchik
  • 3,861
  • 3
  • 34
  • 41