Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Нескінченний цикл». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Нескінченний цикл усередині функції означає, що функція ніколи не повертає керування, тому стек викликів (call stack) ніколи не звільняється. Event loop не може взяти наступне завдання з черги, тож не спрацюють ані таймери, ані колбеки промісів, ані обробники кліків, а браузер перестане перемальовувати інтерфейс. Сторінка «зависає», і врешті браузер показує повідомлення на кшталт «Сторінка не відповідає».** ```javascript setTimeout(() => console.log('I will never run'), 0); while (true) {} // the stack is never released ``` **Ключове:** JavaScript однопотоковий, тому цикл, який не завершується, блокує не одну задачу, а весь застосунок.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Якщо у функції є нескінченний цикл, JavaScript ніколи не звільнить стек викликів, і event loop зупиниться: жодне інше завдання, ані таймери, ані проміси, ані кліки, ані відмальовування інтерфейсу, не зможе виконатися.** Для користувача це виглядає як повністю «зависла» сторінка. ## Теорія ### TL;DR - Нескінченний цикл не дає функції завершитися, тому вона назавжди залишається в стеку викликів (call stack). - Поки стек зайнятий, event loop не може взяти нову задачу з черги. - Не спрацюють ані `setTimeout`, ані `Promise.then`, ані обробники подій. - Браузер перестає перемальовувати UI і згодом пропонує закрити вкладку. - Рішення: розбивати роботу на частини (`setTimeout`, `requestAnimationFrame`) або виносити обчислення у Web Worker. ### Швидкий приклад ```javascript function infinite() { while (true) { console.log('forever...'); } } infinite(); ``` ### Що відбувається крок за кроком 1. Функція `infinite()` потрапляє в **call stack**. 2. Починається виконання циклу `while (true)`, і він **ніколи не завершиться**. 3. Рушій **ніколи не вийде** з функції, а отже: - стек **ніколи не звільниться**, - event loop **не зможе взяти наступну задачу**, - браузер **перестане реагувати** на кліки, скрол, а іноді «зависають» навіть DevTools. ### Чому це відбувається JavaScript це **однопотокова мова**. У кожен момент часу вона може виконувати **лише один шматок коду**, той, що зараз перебуває у **call stack**. Поки функція не завершилась, рушій **не перемкнеться** на інші задачі: ані на `setTimeout`, ані на `Promise.then`. Черга завдань просто накопичується і чекає на вільний стек, якого вже не буде. ### Таймер, який ніколи не спрацює ```javascript setTimeout(() => console.log('I will not run'), 0); while (true) {} // infinite loop ``` Пояснення: - `setTimeout` кладе колбек у **чергу макрозадач**; - поки працює `while (true)`, **стек не звільняється**; - event loop не може дістати задачу з черги; - `console.log('I will not run')` **ніколи не виконається**. ### Наслідки | Наслідок | Опис | | --- | --- | | **Блокування стека** | Код не виходить з функції, тому стек не звільняється | | **Зупинка event loop** | Черги задач (таймери, проміси) не обробляються | | **Зависання сторінки** | UI не перемальовується, браузер може показати «Сторінка не відповідає» | | **Немає реакції на події** | Кліки, скрол, введення тексту не працюють | ### Як уникнути блокування Використовуйте асинхронність або розбиття задачі на частини. Варіант 1: `setTimeout` ```javascript function loop() { console.log('iteration'); setTimeout(loop, 0); // lets the engine breathe between iterations } loop(); ``` Варіант 2: `requestAnimationFrame`, підходить для візуальних задач і анімацій: ```javascript function animate() { // draw a frame requestAnimationFrame(animate); } animate(); ``` Варіант 3: Web Worker, якщо потрібні важкі обчислення. Виносимо їх в окремий потік: ```javascript // worker.js onmessage = e => { while (true) {} // can run long, the UI stays responsive }; ``` ### Підсумок | Термін | Пояснення | | --- | --- | | **Нескінченний цикл у функції** | Ніколи не виходить зі стека викликів | | **Наслідок** | Event loop заблоковано, браузер «завмирає» | | **Рішення** | Ділити роботу на частини (`setTimeout`, `requestAnimationFrame`, Web Workers) | ### Типові помилки - Думати, що `setTimeout(fn, 0)` «перерве» цикл. Колбек лише стає в чергу, а виконається тільки після звільнення стека. - Вважати, що промиси мають перевагу над блокуванням. Мікрозадачі теж чекають на вільний стек. - Виносити важкий цикл у `async` функцію і вважати це асинхронністю. `async` без `await` на реальній асинхронній операції виконується синхронно і так само блокує потік. - Ставити умову виходу, яка ніколи не стає хибною, наприклад забути інкремент лічильника або змінювати копію змінної замість самої змінної. - Робити нескінченну рекурсію замість циклу і чекати «зависання»: тут навпаки швидко впаде `RangeError: Maximum call stack size exceeded`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.