Выбор ответа Senior Event loop и libuv обновлено

setImmediate и setTimeout внутри I/O-колбэка

Вопрос

Код выполняется внутри колбэка fs.readFile. Что гарантированно выведется первым?

fs.readFile(__filename, () => {
  setTimeout(() => console.log("timeout"), 0);
  setImmediate(() => console.log("immediate"));
});

Попробуйте сами

Выберите вариант, и откроется разбор.

Показать ответ и разбор

Коротко

Правильный ответ: immediate: после poll идёт check, таймеры на следующем круге. Колбэк readFile выполняется в фазе poll.

Варианты ответа

  1. timeout: нулевой таймер всегда срабатывает раньше setImmediate
  2. Порядок не определён, как и в главном модуле
  3. immediate: после poll идёт check, таймеры на следующем кругеправильный ответ
  4. immediate, потому что setImmediate это микрозадача

Разбор

Колбэк readFile выполняется в фазе poll. Следующая фаза check, там выполняются колбэки setImmediate, и только потом цикл возвращается к фазе timers. Поэтому внутри I/O-колбэка immediate всегда первый.

Недетерминированность бывает в главном модуле: там порядок зависит от того, успела ли пройти 1 мс (минимальная задержка таймера) к моменту входа в цикл. Поэтому вариант «порядок не определён» верен только для главного модуля. setTimeout(fn, 0) не «всегда раньше», а setImmediate это макрозадача фазы check, не микрозадача.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.

Термины по теме