Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Чому JavaScript вважають однопотоковим». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**«Однопотоковий» означає, що в один момент часу у стеку викликів (Call Stack) перебуває і виконується лише один фрагмент коду.** Нова задача почнеться тільки після завершення попередньої, тому неможливо одночасно щось обчислювати і обробляти подію. Асинхронність не додає другого потоку для вашого коду: довгі операції виконують Web API браузера або API Node.js, а Event Loop лише повертає готові колбеки у вільний стек. ```javascript console.log('1'); setTimeout(() => console.log('2'), 0); console.log('3'); // 1, 3, 2 ``` **Ключове:** один стек викликів, одна задача за раз; паралельність живе поза рушієм JS, у Web API та Web Workers.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**JavaScript називають однопотоковим тому, що в один момент часу у стеку викликів (Call Stack) перебуває і виконується лише один фрагмент коду.** Неможливо одночасно щось обчислювати і, наприклад, обробляти подію: нова задача почнеться тільки після завершення попередньої. ## Теорія ### TL;DR - Один потік виконання, один стек викликів, одна задача за раз. - Код виконується построково: доки не завершиться поточний рядок, наступний не почнеться. - Асинхронні задачі виконуються не всередині JS, а у Web API браузера або в API Node.js. - Event Loop лише повертає готові колбеки в стек, коли той звільниться. - Плюс однопотоковості: немає гонок даних і складної синхронізації. - Мінус: довгі обчислення блокують усе, включно з інтерфейсом. ### Швидкий приклад ```javascript console.log('A'); console.log('B'); console.log('C'); ``` Вивід: ```javascript A B C ``` JS іде построково: доки не виконається `A`, `B` не почнеться. Усе відбувається в одному потоці. ### Що це означає технічно У рушії JavaScript (наприклад, **V8**) є: - **Call Stack**, стек викликів, тобто код, що виконується зараз; - **Event Loop**, цикл подій, який керує асинхронними задачами; - **Callback Queue / Microtask Queue**, черги колбеків і промісів. Але все це обслуговує **один потік** виконання коду. Асинхронні задачі (мережеві запити, таймери тощо) не виконуються всередині JS: ними займається **браузер (Web APIs)** або **API Node.js**, а JS просто отримує сповіщення, коли результат готовий. Схематично: ```text +----------------------+ | Call Stack | <- виконується рівно один шматок коду +----------------------+ ^ +----------------------+ | Event Loop | <- перевіряє, чи вільний стек +----------------------+ ^ +----------------------+ | Callback / Microtask | <- асинхронні задачі чекають своєї черги +----------------------+ ``` ### Приклад з асинхронністю ```javascript console.log('1'); setTimeout(() => console.log('2'), 0); console.log('3'); ``` Вивід: ```javascript 1 3 2 ``` Чому так: - JS спершу виконує синхронний код (`1`, `3`); - потім, коли стек порожній, Event Loop бере задачу з черги (`2`). Навіть із `setTimeout(..., 0)` JS не робить дві справи одночасно. ### Чому це важливо Однопотоковість означає: - **простоту коду**, немає гонок даних і складної синхронізації; - **обмеження**, довгі операції (важкі цикли, обчислення) блокують усе, і інтерфейс «зависає». ```javascript // Такий цикл заморозить сторінку на кілька секунд: const start = Date.now(); while (Date.now() - start < 5000) {} console.log('Only now the UI responds again'); ``` ### А як же багатопотоковість у браузері Хоча сам JS однопотоковий, **браузер і Node.js** мають інші потоки поза рушієм JS: - мережеві запити (XHR, `fetch`); - таймери (`setTimeout`); - файлова система (у Node.js); - Web Workers (фоновий потік, але з обмеженнями, без спільного стану). JS просто **отримує результати** з цих потоків, але сам виконує код лише в одному. ### Підсумок термінів | Термін | Що означає | | --- | --- | | **Однопотоковий** | JS виконує код послідовно, в одному потоці | | **Асинхронність** | Досягається за рахунок Event Loop і черг | | **Web APIs / Node APIs** | Обробляють задачі паралельно, але поза рушієм JS | | **Багатопотоковість** | Лише через Web Workers, без доступу до спільних даних | ### Типові помилки - Думати, що `setTimeout(fn, 0)` виконає колбек негайно: він чекатиме, доки звільниться стек. - Вважати асинхронність паралельністю: асинхронний код усе одно виконується в тому самому потоці. - Робити важкі обчислення в основному потоці замість Web Worker і дивуватися, що інтерфейс не реагує. - Плутати Web Workers зі спільною пам'яттю: воркер має власний контекст, дані передаються повідомленнями. - Забувати, що мікрозадачі (проміси) виконуються раніше за макрозадачі (таймери) після спорожнення стеку.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.