Прежде всего, давайте проясним, что такое EventEmitter
.JavaScript и, следовательно, Node.js asynchronous
.Это означает, что вместо того, чтобы ждать входящих подключений к объекту сервера, вы добавляете listener
к объекту и передаете ему callback function
, который затем, "как только происходит" событие, выполняется.
Там все еще есть ожидание, которое происходит на заднем плане, но это было отвлечено от вас.
Давайте посмотрим на этот простой пример:
// #1) create a new server object, and pass it a function as the callback
var server = net.createServer(function (stream) {
// #2) register a callback for the 'connect' event
stream.on('connect', function () {
stream.write('hello\r\n'); // as
});
// #3) register a callback for the 'data' event
stream.on('data', function (data) {
stream.write(data);
});
// #4) register a callback for the 'end' event
stream.on('end', function () {
stream.write('goodbye\r\n');
stream.end();
});
});
// #5) make the server listen on localhost:8124
server.listen(8124, 'localhost');
Итак, мысоздайте сервер и передайте ему callback function
, эта функция еще не выполнена.Передача функции здесь - это, по сути, ярлык для добавления прослушивателя для события connection
объекта сервера.После этого мы запускаем сервер с #5
.
Что теперь происходит в случае входящего соединения?
Поскольку функция, которую мы передали createServer
, былапривязанный к событию connection
, теперь он выполняется.
Добавляет прослушиватели событий connect
, data
и end
к stream object
(который представляетотдельное соединение) путем подключения обратных вызовов для событий.
После этого stream
запускает событие connect
, поэтому функция, переданная в #2
, выполняется и записывает hello\r\n
до потока.Как функция узнает, в какой поток она должна записать? Замыкания - это ответ, функция наследует область, в которой она была создана, поэтому внутри функции stream
все еще ссылается на отдельное соединение, которое вызвало этот самый обратный вызов, в котором мы сейчас находимся.
Теперь клиент отправляет некоторые данные по соединению, что делает объект stream
вызывающим его событие data
, так как мы привязали функцию к этому событию в #3
, теперь мы отображаем входящиеданные обратно клиенту.
В случае, если клиент закрывает соединение, вызывается функция, которую мы связали в #4
, которая записывает goodbye\r\n
и после этого закрывает соединениес нашей стороны.
Делает ли это что-то более ясным?Ну, это определенно делает все намного проще.Узел, как и JavaScript внутри браузеров, single threaded
.В данный момент времени происходит только одна вещь.
Чтобы описать это просто, все эти callbacks
попадают в глобальную очередь и затем вызываются одна за другой, поэтому эта очередь может (абстрагироваться) выглядетьthis:
| connection event for a new stream
| data event for stream #12
| callback set via setTimeout
v close event of yet another stream
Теперь они выполняются сверху вниз, между ними ничего не произойдет.Нет никаких шансов, что пока вы делаете что-то в callback
, привязанном к событию data
, что-то другое произойдет и волшебным образом изменит состояние системы.Даже если на сервере имеется новое входящее соединение, его событие будет поставлено в очередь, и ему придется ждать, пока все, прежде чем событие data
, в котором вы сейчас находитесь, не завершится.