Node.js/express:立即响应客户端请求并在nextTick中继续执行任务

Miq*_*uel 7 javascript asynchronous node.js express

我想将服务器耗费大量CPU的任务与用户体验区分开来:

./main.js:

var express = require('express');
var Test = require('./resources/test');
var http = require('http');
var main = express();

main.set('port', process.env.PORT || 3000);
main.set('views', __dirname + '/views');
main.use(express.logger('dev'));
main.use(express.bodyParser());
main.use(main.router);

main.get('/resources/test/async', Test.testAsync);

main.configure('development', function() {
  main.use(express.errorHandler());
});

http.createServer(main).listen(main.get('port'), function(){
  console.log('Express server app listening on port ' + main.get('port'));
});
Run Code Online (Sandbox Code Playgroud)

./resources/test.js:

function Test() {}
module.exports = Test;

Test.testAsync = function(req, res) {
  res.send(200, "Hello world, this should be sent inmediately");
  process.nextTick(function() {
    console.log("Simulating large task");
    for (var j = 0; j < 1000000000; j++) {
      // Simulate large loop
    }
    console.log("phhhew!! Finished!");
  });
};
Run Code Online (Sandbox Code Playgroud)

当请求"localhost:3000/resources/test/async"时,我希望浏览器呈现"Hello world,这应该立即发送"真的很快并且node.js继续处理,并且在控制台出现"完成"消息一段时间后.

相反,浏览器一直等待,直到node.js完成大任务,然后呈现内容.我试着res.set({ 'Connection': 'close' });和也res.end();,但没有按预期工作.我也google了没有运气.

应该如何立即将响应发送给客户端,服务器继续执行任务?

编辑

在解决方案中发布fork方法

Pet*_*ons 6

尝试等待而不是占用CPU:

res.send("Hello world, this should be sent inmediately");
console.log("Response sent.");
setTimeout(function() {
  console.log("After-response code running!");
}, 3000);
Run Code Online (Sandbox Code Playgroud)

node.js是单线程的.如果用繁忙的循环锁定CPU,整个过程就会停止,直到完成为止.


Miq*_*uel 5

Thakns在Peter Lyons的帮助下,最终的主要问题是firefox缓冲区:响应时间并不长于刷新它(因此firefox一直在等待)。

无论如何,对于较高的CPU执行任务,节点将一直挂起直到完成,因此将不会参加新的请求。如果有人需要它,可以通过分叉来实现(使用child_process,请参阅http://nodejs.org/api/child_process.html中的示例)

不得不说,通过分叉来改变上下文可能要比将任务分成不同的滴答需要更长的时间。

./resources/test.js:

var child = require('child_process');
function Test() {}
module.exports = Test;

Test.testAsync = function(req, res) {
  res.send(200, "Hello world, this should be sent inmediately");
  var childTask = child.fork('child.js');
  childTask.send({ hello: 'world' });
};
Run Code Online (Sandbox Code Playgroud)

./resources/child.js:

process.on('message', function(m) {
  console.log('CHILD got message:', m);
});
Run Code Online (Sandbox Code Playgroud)