Углубленное размышление о цикле событий узла, вызванном вопросом интервью

Node.js

Эта статья охватывает

  • Введение вопросов интервью
  • У автора есть некоторые вопросы о порядке выполнения вопросов интервью цикла событий.
  • Глубокое понимание микрозадач, циклов событий, таймеров и т. д. с помощью вопросов на собеседовании.
  • общий вывод

вопросы интервью

Вопросы на собеседовании следующие.Вы можете попробовать сначала написать результаты вывода, а затем прочитать мое подробное объяснение ниже, чтобы увидеть, будут ли какие-либо расхождения.Если вы можете выяснить порядок выполнения node.js, это не должно быть проблема.

async function async1(){
    console.log('async1 start')
    await async2()
    console.log('async1 end')
  }
async function async2(){
    console.log('async2')
}
console.log('script start')
setTimeout(function(){
    console.log('setTimeout0') 
},0)  
setTimeout(function(){
    console.log('setTimeout3') 
},3)  
setImmediate(() => console.log('setImmediate'));
process.nextTick(() => console.log('nextTick'));
async1();
new Promise(function(resolve){
    console.log('promise1')
    resolve();
    console.log('promise2')
}).then(function(){
    console.log('promise3')
})
console.log('script end')

Правильный вывод вопросов интервью

script start
async1 start
async2
promise1
promise2
script end
nextTick
async1 end
promise3
setTimeout0
setImmediate
setTimeout3

Задайте вопрос

Когда вы понимаете асинхронность node.js, есть некоторые вещи, которые вы не понимаете Разработчики, использующие node.js, должны знать, что это однопоточный, асинхронный, неблокирующий и высококонкурентный язык, ноКогда node.js реализует асинхронность, запускаются две асинхронные задачи. Это так же просто, как тот, кто быстрее выполнит ее первым, или асинхронная задача также имеет последовательность выполнения в конце? Для однопоточного асинхронного языка это Как добиться высокой параллелизма?

Итак, давайте ответим на эти два вопроса, чтобы по-настоящему понять асинхронность (микрозадачи и циклы событий) в node.js.

Асинхронный синтаксис Node сложнее, чем у браузера, потому что он может взаимодействовать с ядром, и для этого ему нужно создать специальную библиотеку libuv. Эта библиотека отвечает за время выполнения различных callback-функций, и, наконец, асинхронные задачи по-прежнему должны возвращаться в основной поток на основе механизма событийного цикла и ставятся в очередь на выполнение одна за другой.

Объясните подробно

1. Текущий цикл и второй цикл

Асинхронные задачи можно разделить на два типа.

  1. Добавляйте асинхронные задачи в этом раунде циклов
  2. Добавить асинхронную задачу во втором раунде цикла

Так называемая «петля» относится к циклу событий (event loop). Вот как движок JavaScript обрабатывает асинхронные задачи, которые будут подробно объяснены позже. Насколько здесь понятно, текущий цикл должен выполняться раньше, чем второй цикл.

Node предусматривает, что функции обратного вызова process.nextTick и Promise добавляются к текущему циклу, то естьЗадачи синхронизации начинают выполнять их, как только их выполнение завершено.. Функции обратного вызова setTimeout, setInterval и setImmediate добавляются во второй цикл.

2.process.nextTick()

1)Многие друзья не должны рассматривать process.nextTick как второй цикл из-за следующего.

2) Node выполняет все задачи синхронизации, а затем выполняет очередь задач process.nextTick.

3) Если вы хотите максимально быстро выполнить асинхронные задачи в процессе разработки, вы можете использовать процесс .NextTick для завершения.

3. Микрозадачи

Согласно спецификации языка, функция обратного вызова объекта Promise войдет в очередь «микрозадачи» в асинхронной задаче.

Очередь микрозадач добавляется к очереди process.nextTick, которая также принадлежит текущему циклу.

Согласно спецификации языка, функция обратного вызова объекта Promise войдет в очередь «микрозадачи» в асинхронной задаче.

Очередь микрозадач добавляется к очереди process.nextTick, которая также принадлежит текущему циклу. Таким образом, приведенный ниже код всегда выводит сначала 3, а затем 4.

process.nextTick(() => console.log(3));
Promise.resolve().then(() => console.log(4));

//выводим результат 3, 4

process.nextTick(() => console.log(1));
Promise.resolve().then(() => console.log(2));
process.nextTick(() => console.log(3));
Promise.resolve().then(() => console.log(4));

//выводим результат 1, 3, 3, 4

Обратите внимание, что следующая очередь будет выполняться только после того, как предыдущая очередь будет полностью очищена. Концепция двух очередей, nextTickQueue и микро-очереди microTaskQueue, то есть существует несколько типов асинхронных задач, которые открываются, например объекты промисов, которые сразу после открытия входят в микро-очередь, но для разных задач между очереди, все равно будет порядок, который определяется очередью.

4. Стадия цикла обработки событий (простой, подготовка игнорирует эту стадию)

Самое подробное объяснение самой стадии ивентового цикла (официальный сайт:узел будет .org/en/docs/gui…

  1. этап таймеров

    Второй этап включает setTimeout() и setInterval().

  2. IO callbacks

    Большинство событий обратного вызова, обычный обратный вызов

  3. этап опроса

    Сетевое подключение, сбор данных, чтение файлов и т. д.

  4. этап проверки

    setImmediate() вызывает обратный вызов здесь

  5. закрыть этап Некоторые обратные вызовы закрытия, например socket.on('close', ...)

  • Примечания цикла событий

1) Когда Node начинает выполнять скрипт, он сначала инициализирует цикл событий, но в это время цикл событий еще не запущен, и в первую очередь будут выполнены следующие действия.

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

Наконец, после того, как все вышеперечисленное сделано, цикл событий официально начинается.

2) Цикл событий также работает в однопоточной среде, и высокий параллелизм также зависит от цикла событий.Каждый раз, когда генерируется событие, оно будет добавляться в очередь, соответствующую этому этапу.В это время цикл событий достанет события из очереди и подготовит к выполнению callback.

3) Предположим, что цикл обработки событий сейчас перешел на определенную стадию, даже если в других очередях в этот период есть готовые события, все callback-методы текущей очереди будут выполнены перед переходом на следующую стадию.

5. setTimeOut и setImmediate в цикле событий

Так как setTimeout выполняется на этапе таймеров, а setImmediate выполняется на этапе проверки. Таким образом, setTimeout завершится раньше, чем setImmediate.

setTimeout(() => console.log(1));
setImmediate(() => console.log(2));

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

Это связано с тем, что второй параметр setTimeout по умолчанию равен 0. Но на самом деле Node не может сделать 0 миллисекунд, а требуется как минимум 1 миллисекунда Согласно официальной документации диапазон значений второго параметра находится между 1 миллисекундой и 2147483647 миллисекундами. То есть setTimeout(f, 0) эквивалентен setTimeout(f, 1).

В реальном исполнении после входа в цикл событий может быть 1 миллисекунда, а может и не быть 1 миллисекунда, в зависимости от текущей ситуации в системе. Если оно меньше 1 миллисекунды, то фаза таймеров будет пропущена и будет введена фаза проверки, а функция обратного вызова setImmediate будет выполнена первой.

Однако следующий код должен сначала вывести 2, а затем 1.

const fs = require('fs');
fs.readFile('test.js', () => {
 setTimeout(() => console.log(1));
 setImmediate(() => console.log(2));
});

Приведенный выше код сначала войдет в стадию обратных вызовов ввода-вывода, затем в стадию проверки и, наконец, в стадию таймеров. Следовательно, setImmediate будет выполнен раньше, чем setTimeout.

6. Некоторое непонимание асинхронности и промисов в синхронных задачах

  • Вопрос 1:

В этом вопросе интервью, в процессе синхронизации задачи, интересно, есть ли у вас какие-либо вопросы, почему бы не выполнить конечный вывод async1 после вывода async2, а затем выполнить обещание1?

Ответ: Цитата из книги Учителя Жуана Ифэна: «Асинхронная функция возвращает объект Promise. Когда функция выполняется, как только она сталкивается с ожиданием, она сначала возвращается, ждет завершения запущенной асинхронной операции, а затем выполняет оператор за телом функции." Проще говоря, сначала выполните следующий код задачи синхронизации.После завершения выполнения, то есть после разрешения промиса в выражении, продолжайте выполнение асинхронной функции и возвращайте результат решения. (На самом деле это все еще проблема текущего цикла промисов. Окончательное разрешение является асинхронным и находится в конце текущего цикла.)

  • Вопрос 2:

Почему console.log('promise2') также выполняется перед разрешением?

Ответ: Примечание: этот контент взят из книги Ruan Yifeng по ES6.Вызов разрешения или отклонения не прекратит выполнение функции параметра обещания. Поскольку немедленно разрешенный Promiseтекущий циклв конце выполнения, при этом всегдаЗадачи синхронизации позже текущего цикла. После того, как обычный метод написания вызывает resolve или reject, задача Promise завершается, и последующие операции следует размещать после метода then. Так что лучше поместить оператор return перед ним, чтобы не было сюрпризов.

new Promise((resolve,reject) => {
    return resolve(1);
    //后面的语句不会执行
    console.log(2);
}
  • Вопрос 3:

Есть ли сомнения в порядке выполнения обещания3 и завершения сценария?

Ответ: Потому что немедленно разрешенный Promiseтекущий циклв конце выполнения, при этом всегдаЗадачи синхронизации позже текущего цикла. Promise — это функция немедленного выполнения, но ее успешное (или неудачное: отклонение) разрешение функции обратного вызова — это обратный вызов асинхронного выполнения. При выполнении resolve() задача будет помещена в очередь обратного вызова, и цикл обработки событий примет ее, когда стек вызовов освободится. Последнее выполнение в этом цикле.

Общий вывод

Общий итог последовательности таков: Задача синхронизации -> текущий цикл -> второй цикл

Приложение: Ссылки

Официальный сайт Node.js:

Думаете, эта статья была вам полезна? пожалуйста, поделитесь с большим количеством людей

Приглашаю всех обратить внимание на мой официальный аккаунт - руководство по развитию программистов. Пожалуйста, найдите WeChat самостоятельно - "Руководство по развитию программиста"