Leonidas
Leonidas

Reputation: 2160

Why can I execute code after "res.send"?

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?

Upvotes: 115

Views: 67863

Answers (4)

Mukadas Maltiti
Mukadas Maltiti

Reputation: 83

I had a similar issue but the answers provided and the comments helped. Here's my two cents. The code that comes after res.send() still runs although the connection with the client gets closed. In my context, I had a function that checked whether a user existed in my MongoDB db and then return the user else return null.

    export const authenticateUser = async (req: Request, res: Response) => {
   
    const {username, password} = req.body as IUser
    
    const user = await getUser(username) // returns user or null
    
    if(user === null){
        console.log("user is null")
        res.status(404).send("user not found")
    }

    // if user is null the connection get's closed since the above if block runs 
    // but since res.send() doesn't end the function the code below continues to run
    // this causes an error because user is null 

    const passwordMatch = await compare(password, user!.password)

     if(!passwordMatch){
         res.status(400).send("wrong password")
    }
    }

adding an else block should solve this

export const authenticateUser = async (req: Request, res: Response) => {
   
    const {username, password} = req.body as IUser
    
    const user = await getUser(username) // returns user or null
    
    if(user === null){
        console.log("user is null")
        res.status(404).send("user not found")
    }else{
        const passwordMatch = await compare(password, user!.password)

        if(!passwordMatch){
            res.status(400).send("wrong password")
        }
    }
    }

Upvotes: 0

Boris Yakubchik
Boris Yakubchik

Reputation: 4463

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();
 });
});

Upvotes: 0

josh3736
josh3736

Reputation: 145002

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

Upvotes: 171

Marcos Pereira
Marcos Pereira

Reputation: 1176

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.

Upvotes: 54

Related Questions