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

时间:2015-04-13 16:02:14

标签: node.js sockets express

我试图在node.js中实现和现有的解决方案,特别是使用express.js框架。现在,现有解决方案的工作原理如下:

  • 服务器公开客户端可以连接到的
  • 的GET服务
  • 当客户端调用GET服务时,客户端编号递增(全局变量),然后检查客户端数量;
  • 如果没有连接至少3个客户端,则服务处于无限循环状态,等待其他客户端连接
  • 如果(或者更确切地说,当两个客户端的其余部分连接),服务发送响应每个人已经连接了足够的客户端(真正的'值)。

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

现在我不是这些架构的专家,但从我的想法来看,这不是一个正确或好的解决方案。我最初的想法是:这个必须用套接字来解决。但是,由于现有的解决方案就是这样(它不是用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. 为什么这个&#34;逻辑&#34;在C#中工作,但不在express.js中工作?上面的代码挂起,没有处理其他请求。
  3. 我知道node.js是单线程的,但是如果我们有一个更传统的服务立即响应,并且同时有20个请求呢?

2 个答案:

答案 0 :(得分:3)

我可能会为此使用事件发射器:

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语句,而是在创建事件监听器之后从请求处理程序返回。由于请求处理程序是异步的,因此它们的返回值将被丢弃,因此您可以返回任何内容(或任何内容)。作为替代方案,我也可以使用它:

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

此外,即使您从请求处理程序函数返回,事件侦听器仍然引用res变量,因此请求处理程序范围由Node维护,直到事件侦听器回调中的res.json()为止。调用。

答案 1 :(得分:1)

  1. 您的http方法应该有效
  2. 您正在阻止事件循环,因此节点拒绝在while循环中执行任何其他工作
  3. 你真的很亲密,你只需要经常检查,而不是经常检查。我使用process.nextTick()执行此操作,但setTimeout()也适用:

  4. 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());
      })
    });
    */