Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке event loop». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Event loop (цикл подій) - це механізм усередині рушія JavaScript, який керує виконанням коду, обробкою асинхронних операцій і взаємодією між стеком викликів (call stack) та чергами завдань. Він працює як органайзер: коли стек порожній, бере наступне завдання спочатку з черги мікротасків (`Promise.then`, `queueMicrotask`), і лише коли та порожня, з черги макротасків (`setTimeout`, події, I/O). Саме event loop робить однопотоковий JavaScript асинхронним і неблокуючим.** ```javascript console.log('1'); setTimeout(() => console.log('2'), 0); // macrotask Promise.resolve().then(() => console.log('3')); // microtask console.log('4'); // output: 1, 4, 3, 2 ``` **Ключове:** асинхронні колбеки виконуються лише тоді, коли стек викликів порожній, а мікротаски завжди йдуть перед наступною макротаскою.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Event loop (цикл подій) - це механізм усередині рушія JavaScript**, який керує виконанням коду, обробкою асинхронних операцій та взаємодією між стеком викликів (call stack) і чергами завдань (task queues). Саме event loop робить JavaScript асинхронним і неблокуючим, попри те що сама мова однопотокова. ## Теорія ### TL;DR - Event loop вирішує, яка задача виконується зараз, а яка почекає, щоб не блокувати головний потік. - Асинхронний колбек потрапляє в стек лише тоді, коли стек порожній. - Мікротаски (`Promise.then`, `queueMicrotask`) мають вищий пріоритет за макротаски (`setTimeout`, події, I/O). - Після кожної макротаски рушій спустошує всю чергу мікротасків і лише потім бере наступну макротаску. - Якщо синхронний код не завершується, event loop не дійде до черг узагалі. ### Швидкий приклад ```javascript console.log('1'); setTimeout(() => console.log('2'), 0); Promise.resolve().then(() => console.log('3')); console.log('4'); ``` Вивід: ```javascript 1 4 3 2 ``` Чому саме так: 1. Спочатку виконується синхронний код (`1`, `4`). 2. Колбек промісу (`.then`) потрапляє в чергу **мікротасків**. 3. `setTimeout` потрапляє в чергу **макротасків**. 4. Event loop спершу виконує всі мікротаски (`3`), а потім бере наступну макротаску (`2`). ### Основні учасники Щоб зрозуміти event loop, треба знати чотири структури: 1. **Call Stack (стек викликів)** - там виконується поточний код: функції та вирази. 2. **Task Queue / Callback Queue** - черга **макротасків**: таймери, події, `setTimeout`, `setInterval`, I/O. 3. **Microtask Queue** - черга **мікротасків**: `Promise.then()`, `queueMicrotask()`, а в Node.js ще `process.nextTick()`. 4. **Event Loop** - «петля», яка стежить: якщо стек порожній, бере задачу з черги мікротасків; якщо та порожня, бере задачу з черги макротасків. Схематично: ```javascript +--------------------+ | Call Stack | <- runs the current code +---------^----------+ | (empty?) v +--------------------+ | Microtask Queue | <- Promise, queueMicrotask +---------^----------+ | (empty?) v +--------------------+ | Task Queue | <- setTimeout, setInterval, I/O +--------------------+ Event loop checks the queues and moves jobs into the stack ``` ### Як працює event loop покроково 1. JavaScript виконує **синхронний код**, зверху вниз. 2. Коли трапляється **асинхронна операція**, вона передається зовнішнім **Web API** (наприклад, таймер або `fetch`). 3. Коли операція завершується, її колбек потрапляє у відповідну **чергу завдань**. 4. Коли **стек викликів порожній**, event loop бере задачу з черги та кладе її в стек на виконання. 5. Після виконання всіх **мікротасків** event loop переходить до наступної **макротаски**. Це відбувається постійно, у нескінченному циклі. Якщо стек ніколи не звільняється, черги не обробляються зовсім: ```javascript setTimeout(() => console.log('2'), 0); while (true) {} // infinite loop ``` Event loop ніколи не дійде до `setTimeout`, бо стек ніколи не звільниться. Асинхронні задачі виконуються **лише тоді, коли стек порожній**. ### Мікротаски проти макротасків | Тип задачі | Приклади | Коли виконується | | --- | --- | --- | | **Мікротаски** | `Promise.then`, `queueMicrotask` | одразу після поточного коду і перед наступною макротаскою | | **Макротаски** | `setTimeout`, `setInterval`, `fetch`, I/O, DOM events | після всіх мікротасків | Тобто мікротаски мають вищий пріоритет. ### У браузері та в Node.js | Середовище | Особливості event loop | | --- | --- | | **Браузер** | Web APIs дають таймери, `fetch`, події DOM | | **Node.js** | має власні фази (phases): timers, I/O, check, close, `nextTick` тощо | Але в обох випадках ідея одна: один потік, асинхронність через event loop. ### Підсумок | Компонент | Призначення | | --- | --- | | **Call Stack** | виконує поточний код | | **Web APIs** | відпрацьовують асинхронні операції | | **Task Queue** | зберігає колбеки макротасків | | **Microtask Queue** | зберігає проміси та мікрочергу | | **Event Loop** | переносить готові задачі з черг у стек | ### Типові помилки - Вважати, що `setTimeout(fn, 0)` виконає `fn` негайно. Затримка 0 означає лише «якнайшвидше після звільнення стека і всіх мікротасків». - Думати, що event loop є частиною самої мови. Це механізм середовища виконання: браузера або Node.js, а не специфікації ECMAScript. - Плутати пріоритети: проміс, створений пізніше за таймер, усе одно виконається раніше, бо мікротаски йдуть першими. - Породжувати мікротаски всередині мікротасків нескінченно: черга мікротасків спустошується повністю, тому такий цикл заморозить сторінку так само, як `while (true)`. - Очікувати, що `setTimeout(fn, 100)` спрацює рівно через 100 мс. Це мінімальна затримка, реальний час залежить від завантаженості стека.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.