отплыть
Раньше я читал статьи других людей о Наггетс, так что, пожалуйста, поставьте мне лайк. Когда я посещаю github, мне просто нравится смотреть исходный код других людей, и я никогда ничего не загружаю на git. Сегодня мне вдруг захотелось кое-что опубликовать, чтобы я мог проверить это позже, и я также могу дать вам несколько советов, чтобы убедиться, что это правильно. Чтоб не идти все дальше и дальше по ложному пути, и спорить с нужным краснолицым человеком. Ведь раз вы установили неправильную точку зрения, то неправильная точка зрения станет правильной в вашем подсознании.
сомневаться
При нормальных обстоятельствах setTimeout, setInterval, setImmediate и process.nextTick выполняются асинхронно, так каков же механизм и время выполнения этих четырех методов функций и в чем между ними разница? Можно ли его заменить? Все это должно начинаться с цикла событий nodejs. Понимать это.
setTimeout и setInterval
Сначала представим каждую функцию отдельно, setTimeout и setInterval наиболее похожи.Из анализа функций мы знаем, что форматы функций setTimeout и setInterval следующие:
setTimeout(function(arg1,arg2){
//some code
},XXX)
setInterval(function(arg1,arg2){
//some code
},XXX)
Тогда это время задержки XXX имеет условие, и диапазон времени задержки составляет [1,2^31-1]. Когда вы устанавливаете время задержки меньше 1 или больше 2^31-1, время задержки изменяется на 1 по умолчанию, то есть когда вы пишете setTimeout(function(arg1,arg2){},0.1), на самом деле это эквивалентно написанию setTimeout (function(arg1,arg2){},1).
setImmediate и nextTick
Посмотрим непосредственно на код, каков результат выполнения этих двух функций:
setImmediate(function(){
console.log('immediate')
})
process.nextTick(function(){
console.log('next tick')
})
Порядок замены кода
process.nextTick(function(){
console.log('next tick')
})
setImmediate(function(){
console.log('immediate')
})
Мы обнаружили, что вывод кода такой же. Тогда механизм выполнения nextTick предшествует setImmediate.
Механизм исполнения 4 функций
Прежде чем представить механизм 4-х функций, давайте рассмотрим интересное явление.
setTimeout(() => {
console.log('setTimeout')
}, 0)
setImmediate(() => {
console.log('setImmediate')
})
вместо вывода результата
setTimeout
setImmediate
иногда
setImmediate
setTimeout
Почему порядок выполнения этих двух функций так несовместим? Есть ли случайность? На самом деле нет, давайте посмотрим на картинку:
Это схематическая диаграмма всего цикла событий Я удалил много вещей и сократил подробные операции ввода-вывода за один шаг.
Воспользуемся популярным методом расстояния, уровни setTimeout и setInterval одинаковые, поэтому методы прописаны и выполняются последовательно в коде. Но, согласно приведенному выше выводу кода, почему на шагах 1 и 3 происходит случайный вывод?
Функция обратного вызова setTimeout выполняется на этапе 1, а функция обратного вызова setImmediate выполняется на этапе 3. Цикл событий сначала определяет этап 1, что правильно. В официальном документе также говорится, что Цикл цикла событий - это таймеры -> ввод-вывод -> немедленные, промывка и повторение.Но есть проблема, что время входа в первое событие петля неопределенная, не обязательно с нуля
Время, введенное в приведенном выше примере, не является полным. Кто-то в Интернете сделал вывод, что при входе в цикл событий Если время меньше 1 мс, он войдет в этап проверки, то есть этап 3, и вызовет setImmediate.Если он превышает 1 мс, он войдет в этап таймера, который является этапом 1, и вызовет функцию обратного вызова setTimeout. .
Таким образом, мы можем обобщить механизм 4 функций: на этапе 1 (этап таймера) мы регистрируем функции обратного вызова setTimeout и setInterval, а на этапе 3 (этап проверки) после этапа ввода-вывода мы регистрируем обратный вызов функции setImmediate. . Теперь осталась только функция process.nextTick. Эта функция довольно специфична, время ее регистрации находится в фазе галочки зеленой стрелки на рисунке выше.
Используйте несколько вопросов, чтобы углубить свое понимание
Тема 1
const fs = require('fs')
fs.readFile(__filename, () => {
setTimeout(() => {
console.log('setTimeout')
}, 0)
setImmediate(() => {
console.log('setImmediate')
})
})
результат операции:
setImmediate
setTimeout
причина:
таймер -- ввод/вывод -- проверка. Эти три этапа представляют собой последовательность выполнения цикла событий. Когда fs читает файл, мы регистрируем setTimeout и setImmediate в цикле событий. Когда поток файла fs читается, выполняется этап ввода-вывода, а затем выполняется проверка Этап, выполните функцию обратного вызова setImmediate, а затем перейдите к этапу таймера, чтобы выполнить setTimeout при следующем опросе.
тема вторая
setInterval(() => {
console.log('setInterval')
}, 100)
process.nextTick(function tick () {
process.nextTick(tick)
})
результат операции:
无任何输出,setInterval永远不执行
причина:
Поскольку process.nextTick регистрируется в фазе тика, обратный вызов по-прежнему является методом process.nextTick, но process.nextTick не регистрируется в фазе тика следующего опроса, а склеивается в фазе текущего тика и продолжает выполняться. выполнить, что приводит к бесконечному циклу, цикл событий вообще не имеет шансов войти в стадию таймера
### Тема третья
setImmediate(() => { ------ 1
console.log('setImmediate1')
setImmediate(() => { ------2
console.log('setImmediate2')
})
process.nextTick(() => { -------3
console.log('nextTick')
})
})
setImmediate(() => { ------4
console.log('setImmediate3')
})
результат операции:
setImmediate1
setImmediate3
nextTick
setImmediate2
причина:
Сначала зарегистрируйте первый setImmediate на самом внешнем уровне, то есть с меткой 1, а затем зарегистрируйте setImmediate на самом внешнем уровне с меткой 2. Затем зарегистрируйте асинхронную функцию в первом setImmediate. Сначала зарегистрируйте функцию setImmediate с номером 3, а затем зарегистрируйте process.nextTick с номером 4. В это время войдите в цикл событий, чтобы выполнить обратный вызов, сначала выполните функцию в 1 и выведите setImmediate 1. Поскольку и 3, и 4 зарегистрированы после 2, в это время выполняется метод обратного вызова, помеченный 4, и выводится setImmediate3. Продолжайте опрашивать, т.к. process.nextTick прописан в тике после 4, поэтому сначала выполните process.nextTick, лучше всего опрашивать callback-метод исполнения 2, и выводить setImmediate2
тема четвертая
const promise = Promise.resolve()
promise.then(() => {
console.log('promise')
})
process.nextTick(() => {
console.log('nextTick')
})
Выходной результат:
nextTick
promise
причина:
promise.then также регистрируется в фазе тика, но process.nextTick имеет более высокий приоритет, чем promise, поэтому сначала вызовите process.nextTick
пятая тема
setTimeout(() => {
console.log(1)
}, 0)
new Promise((resolve, reject) => {
console.log(2)
for (let i = 0; i < 10000; i++) {
i === 9999 && resolve()
}
console.log(3)
}).then(() => {
console.log(4)
})
console.log(5)
Выходной результат:
2
3
5
4
1
причина:
новое обещание является синхронной операцией, поэтому она выводит 2 и 3, а затем выполняет последнюю строку кода для вывода 5. Далее проблема с promise.then и setTimeout. Мы знаем, что promise.then, как и process.nextTick, регистрируется в фазе тика, а setTimeout — в фазе таймера, сначала он входит в фазу тика для выполнения, а затем входит в setTimeout следующего опроса.
тема шесть
setImmediate(() => {
console.log(1)
setTimeout(() => {
console.log(2)
}, 100)
setImmediate(() => {
console.log(3)
})
process.nextTick(() => {
console.log(4)
})
})
setImmediate(() => {
console.log(5)
setTimeout(() => {
console.log(6)
}, 100)
setImmediate(() => {
console.log(7)
})
process.nextTick(() => {
console.log(8)
})
})
выходной результат
1
5
4
8
3
7
2
6
причина:
Галочки здесь объединены, поэтому 4 и 8 выводятся последовательно
тема семь
setImmediate(() => { ---1
console.log(1)
setTimeout(() => { ---2
console.log(2)
}, 100)
setImmediate(() => { ---3
console.log(3)
})
process.nextTick(() => { ---4
console.log(4)
})
})
process.nextTick(() => { ---5
console.log(5)
setTimeout(() => { ---6
console.log(6)
}, 100)
setImmediate(() => { ---7
console.log(7)
})
process.nextTick(() => { ---8
console.log(8)
})
})
console.log(9)
выходной результат
9
5
8
1
7
4
3
6
2
причина: как показано на рисунке
Пополнить: 1.макротаск: код в скрипте, setTimeout, setInterval, ввод-вывод, визуализация пользовательского интерфейса.
2.микрозадача: обещание, Object.observe, MutationObserver, process.nextTick.