Событие узла L oop Phases Callback - PullRequest
1 голос
/ 11 апреля 2020

Я читал о событиях l oop фазы узла и говорит, что таймеры

  • : эта фаза выполняет обратные вызовы, запланированные с помощью setTimeout () и setInterval ().
  • ожидающие обратные вызовы: выполняет обратные вызовы ввода / вывода, отложенные до следующей итерации l oop.
  • в режиме ожидания, подготовка: используется только для внутреннего использования.
  • опрос: получение новых событий ввода-вывода; выполнять связанные с I / O обратные вызовы (почти все, за исключением закрытых обратных вызовов, запланированных таймерами и setImmediate ()); узел будет блокировать здесь, когда это необходимо.
  • check: здесь вызываются обратные вызовы setImmediate ().
  • обратные вызовы close: некоторые обратные вызовы close, например socket.on ('close', ...).

Так что здесь у меня есть простой код для проверки некоторых фазы выше. Когда вы выполняете код, вы получаете следующий вывод:

  1. close
  2. немедленный
  3. тайм-аут

Но вызовы сокетов в соответствии с do c, последние в фазах. Почему он выполняется первым?

let socket = require("net").createServer();

socket.on("data", function (data) {
  console.log(data.toString());
});

socket.on("close", function (data) {
  console.log("close");
});

socket.listen(8080);

const fs = require("fs");

fs.readFile("readme.txt", () => {
  socket.close();
  setTimeout(() => {
    console.log("timeout");
  }, 0);

  setImmediate(() => {
    console.log("immediate");
  });
});

1 Ответ

1 голос
/ 11 апреля 2020

Прежде всего, имейте в виду, что событие close, вызванное локальным закрытием сокета, не является сетевой операцией. Это не вызвано входящим сетевым событием. Это вызвано реализацией локального сокета, который решает, когда вызывать событие close, чтобы уведомить кого-либо еще, отслеживающего локальный сокет, о том, что он теперь закрыт. Он может даже запускаться синхронно (если библиотека net, которая его реализует, решит это сделать). Таким образом, все, что вы прочитали о том, как сетевые события имеют приоритет или последовательность в событии l oop, здесь не применимо. Это событие не вызывается входящей сетевой операцией и не проходит через событие l oop, как это делает входящая сетевая операция.

Я прошел ваш код в отладчике и вошел в socket.close(), чтобы попробуйте посмотреть, что сделала реализация. Он попадает в эту строку здесь , где звонки this._handle.close(). Это входит в некоторый уровень TCP-оболочки, написанный на C ++, и отладчик не позволит вам проследить его, чтобы увидеть дальше.

Затем эта функция вызывает emitCloseIfDrained(), который вызывает defaultTriggerAsyncIdScope() и передается process.nextTick() в качестве используемого асинхронного механизма.

Итак, кажется, что вызов socket.close() локально заставляет библиотеку сокетов использовать process.nextTick() перед вызовом события close, что придает ей довольно высокий приоритет для обработки перед другими вещами, но будет обрабатываться в будущем тике события l oop.

Но, я надеюсь, вы теперь можете видеть, как это зависит от реализации супер (от того, как событие инициируется в какой-либо вызывающей его библиотеке) и не документировано, поэтому не следует полагаться на вашу реализацию. Желательно понять как можно больше этого для целей интеллектуального любопытства, но вы не должны разрабатывать код, основанный на этом уровне детализации реализации. Особая функция, например, когда событие close срабатывает в сокете, не документирована, и нет никаких обещаний, что оно не изменится в будущем. Если ваш код требует определенной последовательности асинхронных событий, вам нужно написать свой код для управления этой последовательностью, чтобы быть уверенным, что это происходит независимо от уровня детализации реализации.

...