为什么我可以在“ res.send”之后执行代码?

我想知道下面代码行为背后的机制是什么:

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

我的理解是,res.send不是 返回的功能,而是 关闭连接/结束请求。这可以解释为什么我仍然可以在执行 res.send命令后执行代码(我查看了 Express 源代码,它似乎不是一个异步函数)。

还有什么我没注意到的吗?

56570 次浏览

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

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.

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