setInterval 是否阻塞?

Is setInterval blocking?

我有以下节点应用程序

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 window 那么它需要几秒钟才能响应,但是它可以正常工作。

所以我的问题是 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 的一些限制,或者是我的错误。

我认为性能不佳的原因与节点或 setInterval 本身无关,而是与您读取事件数据的方式有关。我做了一些搜索,并在节点上的服务器发送事件的网络上实现了 3 或 4 个不同的示例,它们都遇到了同样的问题。

认为 node.js 对任务没有好处的想法不适合我。

我试过了

  1. 使用process.nextTick
  2. 增加间隔
  3. 使用 setTimeout 代替 setInterval
  4. 与express.js或只是node.js
  5. 使用一些节点模块,例如 connect-sse and sse-stream

我正要开始使用 webworker-threads or the cluster 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> 
    

{编辑}

我还想指出,感谢@Rodrigo Medeiros,使用 curl/api/time 发出请求并没有显示出性能不佳,这强化了浏览器相关问题的想法。