Блокирует ли setInterval?


У меня есть следующее приложение узла

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 + "nn");
}

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

});

Я использую его для использования серверных событий с моим клиентским приложением. Когда я перехожу к http://localhost:8081/api/time он сразу же начинает возвращаться. Если я открою URI в другом окне браузера, то это займет несколько секунд, прежде чем он ответит, однако тогда он работает нормально.

Итак, мой вопрос-блокировка setInterval, или есть какое-то другое объяснение плохой производительности? Исходя из этого ответа он не является предполагалось, что будет, но я не ожидал, что 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 + "nn");
};

Он имеет точно такое же поведение. Так что это выглядит как какое-то ограничение узла, или ошибка со стороны меня.

1 3

1 ответ:

Я думаю, что причина плохой производительности связана не с самим узлом или setInterval, а с тем, как Вы читаете данные о событиях. Я делаю небольшой поиск и реализую 3 или 4 различных примера, найденных в интернете серверных событий, отправленных на узел, и все они страдают от одной и той же проблемы.

Думая, что узел.Джей-ЭС не годился для такой задачи, которая не укладывалась у меня в голове.

Я пытался

  1. использование процесса.nextTick
  2. увеличение интервала
  3. использование setTimeout вместо setInterval
  4. с экспрессом.js или просто узел.js
  5. с некоторыми узловыми модулями, такими как connect-sse и sse-stream

Я собирался начать тестирование с использованием webworker-потоков или кластера модуль или другой серверной платформы пытаются придавить проблему и тогда у меня возникла идея написать небольшую страницу, чтобы захватить события, используя перегруженную EventSource API-интерфейс. Когда я делал это, все работало просто отлично, тем более в предыдущем тесты с использованием Chrome я вижу, что на вкладке Network запрос SSE содержит дополнительную вкладку eventstream, как было замечено, но содержимое было пустым, даже когда данные поступали регулярно.

Это привело меня к мысли, что, возможно, это был браузер, который неправильно интерпретировал запрос, потому что он был запрошен с помощью адресной строки, а не API EventSource. Причин для этого я не знаю но я привел маленький пример и там абсолютно нет бедных спектакль.

Я изменил ваш код вот так.

  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. Создал индекс.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> 
    

{Edit}

Я также хочу отметить, благодаря @Rodrigo Medeiros, что выполнение запроса к /api/time с curl не показывает плохой производительности, которая усиливает идею, что это проблема, связанная с браузером.