Почему setTimeout блокирует мое приложение Node.js?

Возьмите этот код, типичный пример node js примера Http-сервера, на который я добавил задержку в 5 секунд, чтобы смоделировать некоторую работу async, происходящую где-то в другом месте:

const http = require('http');

const hostname = '127.0.0.1';
const port = 8080;

http.createServer((req, res) => {
  setTimeout(()=>{
      res.writeHead(200, { 'Content-Type': 'text/plain' });
      res.end('Hello World\n');
  },5000);
}).listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

Что я ожидаю, так это то, что когда я открываю 5 вкладок, скажем, с задержкой в ​​полсекунды между открытием каждого, сервер должен "отвечать" на каждую вкладку более или менее с такими таймингами:

t=0s - I open first tab
t=0.5s - I open second tab
t=1s - I open third tab
...
t=5s - First tab stops loading, server has replied
t=5.5s - Second tab stops loading, server has replied
t=6s - Third tab stops loading, server has replied
t=6.5s - Fourth tab stops loading, server has replied
t=7s - Fifth tab stops loading, server has replied

Однако поведение, которое я вижу, следующее:

t=0s - I open first tab
t=0.5s - I open second tab
t=1s - I open third tab
...
t=5s - First tab stops loading, server has replied
t=10s - Second tab stops loading, server has replied
t=15s - Third tab stops loading, server has replied
t=20s - Fourth tab stops loading, server has replied
t=25s - Fifth tab stops loading, server has replied

Как будто последующие запросы не запускались, пока первый не завершился. Я что-то упустил? Я думал, что весь смысл node JS должен был иметь возможность запускать асинхронные сигналы из одного потока?

Ответы

Ответ 1

Проблема заключается не в вашем коде или Node.js - как вы настроили свой тест.

Вы ошибочно предположили, что ваш браузер выполнит 5 одновременных запросов, чего не происходит. Различные браузеры имеют разные типы поведения, но обычно браузеры ограничивают очень низкое число максимальным количеством одновременных подключений к одному источнику. Спецификация HTTP дает максимум предложения. Я был очень удивлен, увидев, что Chrome открывает только одно единственное подключение к локальному хосту, так как я знаю, что Chrome открывает 6 для другого происхождения - только что узнал что-то новое!

Используйте другой инструмент для запуска теста, который вы можете контролировать и точно знать, что он выполняет параллельные запросы. Затем вы увидите ожидаемое поведение.

В качестве примера я запустил ваш код и протестировал его с помощью Apache Benchmark, как показано ниже. Параметры показывают: -n 10 состоит в том, чтобы сделать 10 запросов, -c 10 использовать concurrency 10 (т.е. Делать все десять запросов одновременно). Как видно из приведенных ниже результатов, общее время, затраченное на все запросы, составляло ~ 5 с (и "время на запрос" 0,5 с):

~ $ ab -n 10 -c 10 http://127.0.0.1:8080/
This is ApacheBench, Version 2.3 <$Revision: 1663405 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:
Server Hostname:        127.0.0.1
Server Port:            8080

Document Path:          /
Document Length:        12 bytes

Concurrency Level:      10
Time taken for tests:   5.019 seconds
Complete requests:      10
Failed requests:        0
Total transferred:      1130 bytes
HTML transferred:       120 bytes
Requests per second:    1.99 [#/sec] (mean)
Time per request:       5019.151 [ms] (mean)
Time per request:       501.915 [ms] (mean, across all concurrent requests)
Transfer rate:          0.22 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       0
Processing:  5017 5018   0.3   5018    5018
Waiting:     5008 5008   0.2   5008    5009
Total:       5018 5018   0.2   5019    5019
ERROR: The median and mean for the total time are more than twice the standard
       deviation apart. These results are NOT reliable.

Percentage of the requests served within a certain time (ms)
  50%   5019
  66%   5019
  75%   5019
  80%   5019
  90%   5019
  95%   5019
  98%   5019
  99%   5019
 100%   5019 (longest request)

Ответ 2

Кажется, это происходит только в некоторых браузерах, я пытался с сафари, и он работает, как ожидалось. Поэтому я предполагаю, что Chrome одновременно ограничит количество одинаковых запросов на один и тот же ресурс