Express.js – 在发送响应之前循环

我试图在node.js中实现和现有的解决scheme,具体来说,使用express.js框架。 现在,现有的解决scheme如下工作:

  • 服务器公开一个客户端可以连接的GET服务
  • 当客户端调用GET服务时,客户端编号会增加(一个全局variables),然后检查客户端的数量;
  • 如果没有连接至less3个客户端,则服务处于无限循环状态,等待其他客户端连接
  • 如果(或者说是什么时候)两个客户端的其余部分连接,服务发送响应给每个有足够客户端连接的客户(“真”值)。

因此,基本上发生的是,客户端连接并且连接处于活动状态(在一个循环中),直到有足够的客户端连接,然后才有响应(同时对所有客户端)。

现在我不是这些架构的专家,但是从我的想法来看,这不是一个正确的或者很好的解决scheme。 我最初的想法是:这必须用socket来解决。 然而,由于现有的解决scheme是这样的(它不是写在node.js中),我试图模拟这样的行为:

var number = (function(){ var count = 0; return { increase: function() { count++; }, get: function(){ return count; } }; })(); app.get('/test', function(req, res){ number.increase(); while (number.get() < 3) { //hold it here, until enough clients connect } res.json(number.get()); }); 

现在虽然我认为这不是一个正确的解决办法,但我有几个问题:

  1. 除了使用套接字之外,还有别的办法来解决这个问题吗?
  2. 为什么这个“逻辑”在C#中工作,而不是在express.js中? 上面的代码挂起,没有其他请求处理。
  3. 我知道node.js是单线程的,但是如果我们有一个更常规的服务立即响应,并且同时有20个请求呢?

我可能会用这个事件发射器:

 var EventEmitter = require('events').EventEmitter; var emitter = new EventEmitter(); app.get('/', function(req, res) { // Increase the number number.increase(); // Get the current value var current = number.get(); // If it's less than 3, wait for the event emitter to trigger. if (current < 3) { return emitter.once('got3', function() { return res.json(number.get()); }); } // If it's exactly 3, emit the event so we wake up other listeners. if (current === 3) { emitter.emit('got3'); } // Fall through. return res.json(current); }); 

我想强调@Plato是正确的,指出浏览器在响应花费太多时间完成时可能会超时。

编辑 :作为一边,一些解释return emitter.once(...)

上面的代码可以像这样重写:

 if (current < 3) { emitter.once('got3', function() { res.json(number.get()); }); } else if (current === 3) { emitter.emit('got3'); res.json(number.get()); } else { res.json(number.get()); } 

但不是使用这些if/else语句,而是在创build事件侦听器之后从请求处理程序返回。 由于请求处理程序是asynchronous的,所以它们的返回值被丢弃,所以你可以返回任何东西(或者什么都不)。 作为替代,我也可以使用这个:

 if (current < 3) { emitter.once(...); return; } if (current === 3) { ...etc... 

此外,即使您从请求处理函数返回,事件侦听器仍然引用resvariables,所以请求处理程序作用域由Node维护,直到res.json()事件侦听器callback中的res.json()

  1. 你的http方法应该可以工作
  2. 您正在阻止事件循环,因此节点在while循环中拒绝执行任何其他工作
  3. 你真的很接近,你只需要时不时的检查一下。 我使用process.nextTick()执行下面的操作,但是setTimeout()也会起作用:

 var number = (function(){ var count = 0; return { increase: function() { count++; }, get: function(){ return count; } }; })(); function waitFor3(callback){ var n = number.get(); if(n < 3){ setImmediate(function(){ waitFor3(callback) }) } else { callback(n) } } function bump(){ number.increase(); console.log('waiting'); waitFor3(function(){ console.log('done'); }) } setInterval(bump, 2000); /* app.get('/test', function(req, res){ number.increase(); waitFor3(function(){ res.json(number.get()); }) }); */