是否setInterval阻塞?

时间:2015-06-24 16:23:36

标签: javascript node.js event-loop

我有以下节点应用程序

var express = require("express"),
    app = express();


app.get("/api/time", function(req, res) {
    sendSSE(req, res);
});

function sendSSE(req, res) {
    res.set({
        "Content-Type": "text/event-stream",
        "Cache-Control": "no-cache",
        "Connection": "keep-alive",
        "Access-Control-Allow-Origin": "*"
    });

    var id = (new Date()).toLocaleTimeString();

    setInterval(function() {
        constructSSE(res, id, (new Date()).toLocaleTimeString());
    }, 5000);

    constructSSE(res, id, (new Date()).toLocaleTimeString());
};


function constructSSE(res, id, data) {
    res.write("id: " + id + "\n");
    res.write("data: " + data + "\n\n");
}

var server = app.listen(8081, function() {

});

我正在使用它与我的客户端应用程序一起使用服务器端事件。当我浏览http://localhost:8081/api/time时,它会立即开始返回。如果我在另一个浏览器窗口中打开URI,那么它在响应之前需要几秒钟,但是它可以正常工作。

所以我的问题是setInterval阻塞,还是对性能不佳有其他解释?基于this answer它不应该是,但我不希望constructSSE需要5秒。但是,我发现了一个问题。

感谢。

更新 根据建议,它可能与express有关,我删除了它并使用了http模块。

var http = require("http");

http.createServer(function(req, res){
    if (req.url == "/api/time") {
        sendSSE(req, res);
    }
}).listen(8081);

function sendSSE(req, res) {
    res.writeHead(200, {
        "Content-Type": "text/event-stream",
        "Cache-Control": "no-cache",
        "Connection": "keep-alive",
        "Access-Control-Allow-Origin": "*"
    });

    var id = (new Date()).toLocaleTimeString();

    setInterval(function() {
        constructSSE(res, id, (new Date()).toLocaleTimeString());
    }, 5000);

    constructSSE(res, id, (new Date()).toLocaleTimeString());
};


function constructSSE(res, id, data) {
    res.write("id: " + id + "\n");
    res.write("data: " + data + "\n\n");
};

它具有完全相同的行为。所以它看起来像Node的一些限制,或者是我的错误。

1 个答案:

答案 0 :(得分:2)

我认为性能不佳的原因与节点或setInterval本身无关,而是与您读取事件数据的方式有关。我做了一些搜索,并在节点上的Server Sent Events网站上找到了3到4个不同的例子,他们都遇到了同样的问题。

认为node.js不适合这项任务并不适合我的想法。

我试过

  1. 使用process.nextTick
  2. 增加间隔
  3. 使用setTimeout而不是setInterval
  4. 使用express.js或只是node.js
  5. 使用某些节点模块,例如connect-ssesse-stream
  6. 我即将开始使用webworker-threadscluster module或其他服务器平台进行测试,试图解决问题,然后我有了写一个小页面以使用EventSource获取事件的想法API。当我这样做时一切都运行得很好,而且在以前使用Chrome的测试中我看到在网络选项卡中SSE请求包含一个名为EventStream的附加选项卡,但是内容为空即使数据也是如此经常到达。

    这让我相信,由于使用地址栏而不是EventSource API请求,浏览器可能无法以错误的方式正确解释请求。原因我不知道,但我做了一个例子,绝对没有糟糕的表现。

    我改变了你的代码。

    1. 添加了另一条路径到网站根目录进行测试

      var express = require("express"),
      app = express();
      
      // Send an html file for testing
      app.get("/", function (req, res, next) {
          res.setHeader('content-type', 'text/html')
          fs.readFile('./index.html', function(err, data) {
              res.send(data);
          });
      });
      
      app.get("/api/time", function(req, res) {
          sendSSE(req, res);
      });
      
    2. 创建了index.html文件

      <head>
          <title>Server-Sent Events Demo</title>
          <meta charset="UTF-8" />
          <script>
              document.addEventListener("DOMContentLoaded", function () {
                  var es = new EventSource('/api/time'),
                      closed = false,
                      ul = document.querySelector('ul');
      
                  es.onmessage = function (ev) {
                      var li;
                      if (closed) return;
      
                      li = document.createElement("li");
                      li.innerHTML = "message: " + ev.data;
                      ul.appendChild(li);
                  };
      
                  es.addEventListener('end', function () {
                      es.close()
                      closed = true
                  }, true);
      
                  es.onerror = function (e) {
                      closed = true
                  };
              }, false);
          </script>
      </head>
      <body>
          <ul>
          </ul>
      </body> 
      
    3. <强> {编辑}

      我还要指出,感谢@Rodrigo Medeiros,向/api/time curl提出请求表明没有糟糕的表现,这加强了与浏览器相关的问题。