#javascript #node.js #event-loop
#javascript #node.js #цикл событий
Вопрос:
Я прочитал официальную документацию и многие другие блоги process.nextTick()
, но я немного запутался в некоторых темах.
Во-первых, написано, что обратные process.nextTick()
вызовы выполняются перед началом следующей итерации.
Во-вторых, когда внутри цикла ввода-вывода цикл событий в настоящее время находится в фазе опроса. И после фазы опроса цикл событий переходит к фазе проверки, где выполняются любые обратные вызовы, вызываемые в setImmediate
методе.
Теперь в следующем коде
const fs = require('fs');
function main() {
fs.readFile('./xy.txt', function(err, buff){
setTimeout(()=> console.log("timeout inside fs"),0);
setImmediate(()=> console.log("immediate inside fs"));
process.nextTick(()=>{console.log("process.nextTick")});
console.log("inside fs");
})
console.log("called inside main fn in first-iteration");
}
main();
console.log("called in first-iteration);
Вывод будет:
called inside main fn in first-iteration
called in first iteration
Во время этого будет зарегистрирован обратный вызов fs fn, и вышеупомянутые две строки будут утешены, поскольку сценарий ввода будет запущен без цикла событий. И теперь начнется первая итерация цикла событий, начиная с фазы таймера, поскольку таймеры отсутствуют, он перейдет к фазе ожидания, а затем к фазе опроса, где происходит обратный вызов (обратный вызов fs fn), цикл событий начинает выполнение обратного вызова fs итеперь setTimeout
обратный вызов и setImmediate
обратный вызов будут зарегистрированы. После этого process.nextTick
обратный вызов будет зарегистрирован в nextTickQueue, который будет выполнен на следующей итерации или тике (вторая итерация). Теперь, после завершения фазы опроса, мы inside fs
вошли в третью строку.
Затем цикл событий должен перейти к фазе проверки, где setImmediate
присутствует обратный вызов и должен регистрироваться immediate inside fs
, после чего цикл событий должен перейти к следующим фазам, и первая итерация должна завершиться. Перед началом второй итерации process.nextTick
он должен быть зарегистрирован, а затем timeout inside fs
, наконец, должен быть зарегистрирован.
Таким образом, конечный результат будет:
called inside main fn in first-iteration
called in first iteration
inside fs
immediate inside fs
process.nextTick
timeout inside fs
Но вместо этого вывод получается:
called inside main fn in first-iteration
called in first iteration
inside fs
process.nextTick
immediate inside fs
timeout inside fs
где-то было написано, что микрозадачи (process.nextTick) выполняются с наивысшим приоритетом, и поэтому цикл событий оставит все свое выполнение и выполнит микрозадачу на первый взгляд. Но если это тоже так, почему inside fs
утешается раньше process.nextTick
?
В принципе, я в замешательстве, как происходит process.nextTick()
и проходит цикл событий по фазам?
Ответ №1:
Одно из самых больших заблуждений среди разработчиков узлов заключается в том, что process.nextTick запускает код в следующем тике (итерации)
Прежде чем ответить на ваш вопрос, позвольте мне рассказать вам несколько вещей:
process.nextTick()
технически не является частью цикла событий. Вместо этого nextTickQueue будет обработан после завершения текущей операции, независимо от текущей фазы цикла событий.Очередь следующего тика отображается отдельно от других четырех основных очередей, поскольку она изначально не предоставляется libuv, но реализована в Node
Перед каждой фазой цикла событий (очередь таймеров, очередь событий ввода-вывода, очередь немедленных действий, очередь обработчиков закрытия — это четыре основные фазы), прежде чем перейти к фазе, узел проверяет очередь nextTick для любых событий в очереди. Если очередь не пуста, узел начнет обрабатывать очередь немедленно, пока очередь не опустеет, прежде чем перейти к следующему этапу цикла событий.
В Node v11 внесены некоторые изменения, которые существенно меняют порядок выполнения обратных вызовов nextTick, Promise, setImmediate и setTimeout, начиная с Node v11.
Очереди обратного вызова nextTikcs и promise обрабатываются между каждым таймером и немедленным обратным вызовом независимо от того, есть ли другие тайм-ауты обратного вызова и обратный вызов immidate, уже присутствующие в соответствующей очереди.
Запустите это https://repl.it/@sandeepp2016/processNextTick#index.js в предыдущих nodejs11 и nodejs11 и выше вы увидите разницу в порядке выполнения.
Вы почти правильно поняли поток, за исключением того, когда nextTick
вызывается и как синхронный и синхронный код выполняется в Nodejs.
Когда цикл событий переходит в фазу опроса, он выполняет fs.read
обратный вызов, помещенный в очередь событий ввода-вывода. Поскольку в очереди больше нет обратных вызовов событий ввода-вывода, цикл событий перейдет к фазе проверки, но перед запуском обратных вызовов фазы проверки он выполнит все nexttikcs
и поставит задачи в очередь. Вот почему process.nexttick
в вашем случае он был напечатан, а затем immediate inside fs
после фазы проверки он вернется к фазе таймера и распечатает timeout inside fs.
На ваш последний вопрос, когда программа входит в main
функцию, первые три вызова являются асинхронными, первые два будут поставлены в очередь в цикл событий. Но console.log("inside fs")
он немедленно будет помещен в стек вызовов и выполнен основным потоком Nodejs. process.next
также будет выполняться асинхронно (не является частью цикла событий libuv), но после фазы опроса и перед фазой проверки, как показано на изображении.Следовательно, он будет печататься inside fs
раньше process.nextTick
.
Имейте в виду, что цикл событий обрабатывает только асинхронный код, синхронный код выполняется непосредственно в основном потоке без цикла событий.
Для получения более подробной информации прочитайте это
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
Комментарии:
1. большое спасибо, вы определенно оказали большую помощь. Я пройдусь по блогам и задам любые дополнительные запросы.
2. Я хотел бы связаться с вами, пожалуйста, проверьте ваш подключенный
3. Я рад, что это помогло.