Здравствуйте, пытаюсь разобраться в тонкостях эвентлупа в JavaScript'е.
Судя по
этому докладу, примерный псевдокод эвентлупа выглядит вот так:
// EVENTLOOP
while (true) {
task = taskQueue.pop()
execute(task)
while (microtaskQueue.hasTasks()) {
doMicroTask()
}
if (isRepaintTIme()) {
doAnimationTask(task)
repaint()
}
}
А так же, судя по плану выполнения
визуализатору эвентлупа, сначала выполняются таски, потом микротаски и в конце рендер.
Судя по этому плану эвентлупа, код:
setTimeout(() => console.log('timeout'), 0);
Promise.resolve('promise resloved').then(res => console.log(res))
должен сначала вывести
timeout
так как очередь тасков пуста и мы добавили таск setTimeout, а потом промис
promise resloved
. Но выполняется, конечно, сначала промис, а потом таймаут. Как будто начальное выполнение всего этого кода уже и есть таск. Либо как будто первая итерация эвентлупа пропускает таски и начинает сразу с микротасков.
Даже в визуализаторе эвентлупа,
в этом примере, выполняя этот код по шагам, при первом проходе заход в пункт 2: Run a Task почему-то пропускается. А вот если в setTimeout'е добавить создание микротаски, то во второй итерации эвентлупа пункт 2 не пропускается и в таску
визуализатор заходит нормально.
Можно подумать, что это от того, что setTimeout выполняется не моментально, а с задержкой 4 мс, но если модифицировать код, чтобы setTimeout точно успел отработать, результат не изменится:
setTimeout(() => console.log('timeout'), 0);
// отбросим потенциальную задержку от не мгновенного исполнения setTimeout
for (let i = 0; i < 10e8; i++) {}
Promise.resolve('promise resloved').then(res => console.log(res))
Почему реальное поведение отличается от псевдокода и визуализатора для первой итерации эвентлупа?