Задание 1
<html> <head> <title>Task 1</title> </head> <body> <div id="container">0</div> <script> document.addEventListener("DOMContentLoaded", () => { const hostEl = document.getElementById("container"); let counter = 0; while (true) { hostEl.innerText = counter++; } }); </script> </body> </html>
Задание 2
<html> <head> <title>Task 2</title> </head> <body> <div id="container">0</div> <script> document.addEventListener("DOMContentLoaded", () => { const hostEl = document.getElementById("container"); let counter = 0; while (true) { setTimeout(() => { hostEl.innerText = counter++; }, 10); } }); </script> </body> </html>
Задание 3
<html> <head> <title>Task 3</title> </head> <body> <div id="container">0</div> <script> document.addEventListener('DOMContentLoaded', () => { const hostEl = document.getElementById('container'); let counter = 0; const func = () => { setTimeout(() => { hostEl.innerText = counter++; func(); }, 10) }; func(); }) </script> </body> </html>
Задание 4
<html> <head> <title>Task 4</title> </head> <body> <div id="container"> 0 </div> <script> document.addEventListener('DOMContentLoaded', () => { const hostEl = document.getElementById('container'); let counter = 0; const func = () => { new Promise(res => { hostEl.innerText = counter++; res(); }) .then(() => func()); }; func(); }); </script> </body> </html>
🎯 Зачем спрашивают
- Проверить понимание модели выполнения JS (event loop) и различий между:
- синхронным и асинхронным кодом
- макро- и микрозадачами,
- временем рендеринга браузера.
- Проверить, умеет ли кандидат объяснить, почему UI блокируется и как этого избежать.
- Понять, насколько глубоко кандидат понимает взаимодействие JS и браузера (critical rendering path, render blocking).
📝 Ответ
Задача 1
<html> <head> <title>Task 1</title> </head> <body> <div id="container">0</div> <script> document.addEventListener("DOMContentLoaded", () => { const hostEl = document.getElementById("container"); let counter = 0; while (true) { hostEl.innerText = counter++; } }); </script> </body> </html>
while цикла. Даже 0 не отобразится.
Задача 2
<html> <head> <title>Task 2</title> </head> <body> <div id="container">0</div> <script> document.addEventListener("DOMContentLoaded", () => { const hostEl = document.getElementById("container"); let counter = 0; while (true) { setTimeout(() => { hostEl.innerText = counter++; }, 10); } }); </script> </body> </html>
while цикла. Даже 0 не отобразится. setTimeout не решит проблему, так как вызывается внутри бесконечного цикла.Задача 3
<html> <head> <title>Task 3</title> </head> <body> <div id="container">0</div> <script> document.addEventListener('DOMContentLoaded', () => { const hostEl = document.getElementById('container'); let counter = 0; const func = () => { setTimeout(() => { hostEl.innerText = counter++; func(); }, 10) }; func(); }) </script> </body> </html>
setTimeout создаёт новый таймер, но предыдущий уже отработал к моменту создания нового, поэтому таймеры не копятся.
func() происходит через Event Loop после завершения предыдущего. Поэтому стек вызовов не переполнится.Задача 4
<html> <head> <title>Task 4</title> </head> <body> <div id="container"> 0 </div> <script> document.addEventListener('DOMContentLoaded', () => { const hostEl = document.getElementById('container'); let counter = 0; const func = () => { new Promise(res => { hostEl.innerText = counter++; res(); }) .then(() => func()); }; func(); }); </script> </body> </html>
new Promise(res => { hostEl.innerText = counter++; res(); })
res() вызывается синхронно, поэтому .then(() => func()) ставит микрозадачу..then запускается в микроочереди. Внутри он снова вызывает func(), которая тут же создаёт новый Promise и снова синхронно резолвит его, добавляя ещё одну микрозадачу.innerText не успеют нарисоваться).⚖️ Компромиссы
🔎 Встречные вопросы
- Почему
setTimeoutне спасает в задаче №2?
- Чем микрозадачи отличаются от макрозадач?
- Почему
Promiseрекурсия “вешает” вкладку?
- Как сделать счётчик, который не блокирует UI?
- Когда лучше использовать
requestAnimationFrameвместо таймера?
🚩 Красные флаги
- Ответы вроде «всё будет работать» без упоминания event loop.
- Путаница между макро и микрозадачами.
- Упоминание «setTimeout всегда решает проблему блокировки».
- Нет объяснения, почему рендер не происходит.
🛠 Практика
📚 Источники / ссылки
YouTubeWhat the heck is the event loop anyway? | Philip Roberts | JSConf EU
What the heck is the event loop anyway? | Philip Roberts | JSConf EU
JavaScript programmers like to use words like, “event-loop”, “non-blocking”, “callback”, “asynchronous”, “single-threaded” and “concurrency”. We say things like “don’t block the event loop”, “make sure your code runs at 60 frames-per-second”, “well of course, it won’t work, that function is an asynchronous callback!” If you’re anything like me, you nod and agree, as if it’s all obvious, even though you don’t actually know what the words mean; and yet, finding good explanations of how JavaScript actually works isn’t all that easy, so let’s learn! With some handy visualisations, and fun hacks, let’s get an intuitive understanding of what happens when JavaScript runs. Transcript: http://2014.jsconf.eu/speakers/philip-roberts-what-the-heck-is-the-event-loop-anyway.html License: For reuse of this video under a more permissive license please get in touch with us. The speakers retain the copyright for their performances.
MDN Web DocsJavaScript execution model - JavaScript | MDN

JavaScript execution model - JavaScript | MDN
This page introduces the basic infrastructure of the JavaScript runtime environment. The model is largely theoretical and abstract, without any platform-specific or implementation-specific details. Modern JavaScript engines heavily optimize the described semantics.
jaffathecakeTasks, microtasks, queues and schedules
Tasks, microtasks, queues and schedules
When I told my colleague Matt Gaunt I was thinking of writing a piece on microtask queueing and execution within the browser's event loop, he said "I'll be honest with you Jake, I'm not going to read that". Well, I've written it anyway, so we're all going to sit here and enjoy it, ok?