Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Блокуюча операція». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Блокуюча операція займає єдиний потік JavaScript і не віддає стек викликів (call stack), доки не завершиться. Поки вона виконується, event loop не може взяти жодного нового завдання: інтерфейс «зависає», кнопки не натискаються, анімації стоять, колбеки таймерів і відповіді мережі чекають у черзі. Навіть `setTimeout(fn, 0)` не врятує: його колбек потрапить у чергу, але виконається лише після звільнення стека.** ```javascript console.log('1'); setTimeout(() => console.log('2'), 0); const start = Date.now(); while (Date.now() - start < 3000) {} // blocking loop, 3 seconds console.log('3'); // output: 1, then a 3 second pause, then 3, then 2 ``` **Ключове:** блокування зупиняє не одну задачу, а весь застосунок, бо потік у JavaScript один.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Блокуюча операція - це задача, яка тримає єдиний потік JavaScript і зупиняє виконання всього іншого коду.** Поки вона триває, event loop (цикл подій) чекає, тому інтерфейс «зависає», кнопки не натискаються, а анімації та мережеві запити не обробляються. ## Теорія ### TL;DR - JavaScript працює в одному потоці, у стеку викликів (call stack) одночасно може бути лише одна задача. - Довгий синхронний код займає весь потік, решта задач чекає. - Event loop не може взяти нічого з черги, доки стек не звільниться. - `setTimeout(..., 0)` не рятує: колбек стає в чергу, але не виконується під час блокування. - Рішення: розбивати важкі задачі на частини, виносити обчислення у Web Workers, у Node.js брати асинхронні API замість `*Sync`. ### Швидкий приклад ```javascript console.log('A'); function block(ms) { const start = Date.now(); while (Date.now() - start < ms) {} } block(3000); // block the thread for 3 seconds console.log('B'); ``` Вивід: ```javascript A (pause of 3 seconds) B ``` Поки виконується `while`, JavaScript не може робити нічого іншого: не обробляє кліки, не запускає таймери, не оновлює інтерфейс. Це і є blocking. ### Чому це відбувається JavaScript працює в **одному потоці (single thread)**: в один момент часу у **стеку викликів (call stack)** може виконуватись лише **одна задача**. Коли туди потрапляє довгий код, він займає весь потік, і решта задач, зокрема асинхронних, чекає, доки він завершиться. Навіть якщо у вас стоїть `setTimeout`, він не виконається, доки стек не звільниться. Схематично: ```javascript +----------------------+ | Call Stack | <- runs the blocking operation | (busy for a long | | time) | +----------------------+ | Event loop waits Callback queue waits ``` Жодна асинхронна задача не може потрапити в стек, доки блокуюча не завершиться. ### Що стається з асинхронним кодом під час блокування ```javascript console.log('1'); setTimeout(() => console.log('2'), 0); const start = Date.now(); while (Date.now() - start < 3000) {} // blocking loop, 3 seconds console.log('3'); ``` Вивід: ```javascript 1 (pause of 3 seconds) 3 2 ``` `setTimeout(..., 0)` не допоміг: його колбек потрапив у чергу, але не міг виконатися, доки стек не звільнився після `while`. ### Типові блокуючі операції | Операція | Чому блокує | | --- | --- | | Довгий `while` / `for` | займає процесор | | Великі обчислення (рекурсія, сортування, криптографія) | блокують потік | | `alert()`, `prompt()` | зупиняють виконання скрипта | | `sync`-версії методів Node.js (`fs.readFileSync`) | чекають на результат | | Довгі перетворення JSON (`JSON.stringify(hugeObject)`) | виконуються синхронно | ### Як уникнути блокування Розбивати великі задачі на частини (через `setTimeout` або `requestIdleCallback`): ```javascript function bigTask() { for (let i = 0; i < 1e9; i++) { if (i % 1e6 === 0) console.log(i); } } setTimeout(bigTask, 0); // scheduled asynchronously, does not block the interface ``` Використовувати Web Workers для важких обчислень в окремому потоці: ```javascript // worker.js onmessage = (e) => { const result = e.data ** 2; postMessage(result); }; ``` У Node.js брати `fs.promises` замість `fs.readFileSync`. ### Підсумок Уявіть, що у вас один офіціант (потік JavaScript): - **Блокуючий** код: офіціант стоїть біля плити і чекає, доки приготується страва, і нікого не обслуговує. - **Неблокуючий** код: він передає замовлення на кухню і йде до наступного столика. JavaScript працює як другий варіант. Але якщо офіціант сам почне 10 хвилин мішати суп (CPU-heavy код), обслуговування зупиниться. | Термін | Що означає | | --- | --- | | **Блокуюча операція** | задача, яка зупиняє виконання решти коду | | **Результат** | event loop «заморожується», інтерфейс не реагує | | **Приклади** | довгі цикли, sync-функції, `alert()`, великі обчислення | | **Як уникнути** | асинхронні API, Web Workers, поділ задачі на частини | ### Типові помилки - Вважати, що `setTimeout(fn, 0)` робить код асинхронним «всередині»: воно лише переносить виклик на пізніше, сама функція так само заблокує потік. - Використовувати `fs.readFileSync` у HTTP-обробнику: один повільний диск зупиняє обслуговування всіх запитів. - Серіалізувати гігантський об'єкт через `JSON.stringify` у головному потоці, замість потокової обробки або воркера. - Плутати «довгий запит до сервера» з блокуванням: очікування мережі не блокує потік, блокують саме обчислення. - Думати, що `await` звільняє потік від важкого синхронного коду всередині функції: після `await` код усе одно виконується в головному потоці.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.