Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Web Workers у JavaScript». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Web Worker це окремий потік виконання JavaScript, який працює паралельно з головним потоком (UI thread) і тому не блокує інтерфейс.** Головний потік створює його через `new Worker('worker.js')`, а далі обидві сторони спілкуються лише повідомленнями: `postMessage` надсилає дані, `onmessage` їх приймає. Передача асинхронна, дані копіюються алгоритмом structured clone, а не передаються за посиланням. Воркер не бачить DOM, `window`, `document`, `alert()` і `localStorage`, зате має `fetch`, `XMLHttpRequest`, `WebSocket`, `setTimeout`, `indexedDB` та `crypto`. Існує три типи: Dedicated Worker (один на один), Shared Worker (спільний для кількох вкладок) і Service Worker (проксі між сторінкою та мережею). ```javascript const worker = new Worker('worker.js'); worker.postMessage(1e9); worker.onmessage = (event) => console.log('Result:', event.data); ``` **Ключове:** важкі обчислення виконуються у фоновому потоці, спілкування тільки через повідомлення, доступу до DOM у воркера немає.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Web Worker це окремий потік виконання JavaScript-коду, який працює паралельно з головним потоком (UI thread).** Він не блокує інтерфейс: важкі обчислення виконуються у фоні, а результат повертається в головний потік повідомленням. ## Теорія ### TL;DR - JavaScript у браузері однопотоковий: рендеринг, обробка подій і ваш код живуть в одному потоці. - Важкий синхронний цикл займає Event Loop, і сторінка «замерзає». - Web Worker виносить обчислення в окремий потік, тому UI лишається чуйним. - Спілкування між потоками йде тільки через повідомлення: `postMessage` та `onmessage`, дані серіалізуються алгоритмом structured clone. - Воркер не має доступу до `document`, `window`, `alert()`, `localStorage`, але має `fetch`, `XMLHttpRequest`, `WebSocket`, `setTimeout`, `indexedDB`, `crypto`. - Типів три: Dedicated Worker, Shared Worker, Service Worker. ### Швидкий приклад ```javascript // main.js const worker = new Worker('worker.js'); worker.postMessage(1e9); // надсилаємо задачу worker.onmessage = (event) => { console.log('Result:', event.data); }; ``` ```javascript // worker.js onmessage = (event) => { let sum = 0; for (let i = 0; i < event.data; i++) sum += i; postMessage(sum); // повертаємо результат назад }; ``` Тепер важкий розрахунок виконується у фоні, а UI лишається чуйним. ### Проблема однопотокового JavaScript JavaScript у браузері однопотоковий, тобто в одному потоці відбувається все одразу: - рендеринг сторінки - обробка подій - виконання вашого коду Якщо в цьому потоці запустити важкий цикл: ```javascript for (let i = 0; i < 1e9; i++) {} console.log('Done!'); ``` сторінка «замерзне»: інтерфейс перестане реагувати, доки цикл не закінчиться, бо Event Loop зайнятий. ### Як це працює під капотом 1. Головний потік створює воркера через `new Worker('script.js')`. 2. Браузер запускає окремий потік JS. 3. Спілкування між потоками йде через повідомлення (message passing). 4. Передача асинхронна, дані серіалізуються (structured clone). 5. Воркер не має доступу до DOM, `window` і `document`. #### Обмін даними (message passing) Комунікація йде через події `postMessage` і `onmessage`: ```javascript // main.js worker.postMessage({ action: 'sum', a: 5, b: 7 }); // worker.js onmessage = (e) => { if (e.data.action === 'sum') { postMessage(e.data.a + e.data.b); } }; ``` Передавати можна: - рядки, числа, об'єкти - `ArrayBuffer`, `Blob`, `File`, `ImageBitmap` - навіть Transferable об'єкти, щоб передавати без копіювання ### Обмеження та доступне API Web Worker ізольований: - немає доступу до `document`, `window`, `alert()`, `localStorage` - є доступ до `fetch`, `XMLHttpRequest`, `WebSocket`, `setTimeout`, `indexedDB`, `crypto` і подібного #### Потокова обробка даних у воркері Воркер може використовувати Streams і Fetch API: ```javascript onmessage = async (e) => { const response = await fetch(e.data.url); const text = await response.text(); postMessage(text.length); }; ``` Так можна обробляти мережеві дані у фоні, взагалі не блокуючи UI. ### Види Web Workers | Тип | Де використовується | Особливості | | --- | --- | --- | | **Dedicated Worker** | Один на одного | Працює лише зі скриптом, який його створив | | **Shared Worker** | Кілька вкладок або скриптів | Один воркер для всіх сторінок (за origin + URL) | | **Service Worker** | Між браузером і мережею | Кешує запити, працює навіть офлайн | #### Приклад Shared Worker ```javascript // shared-worker.js onconnect = (event) => { const port = event.ports[0]; port.onmessage = (e) => { port.postMessage(`Received: ${e.data}`); }; }; ``` Кілька вкладок можуть під'єднуватися до одного Shared Worker, наприклад щоб обмінюватися даними між вкладками. #### Service Worker як окремий тип > Service Worker це не просто потік, а «проксі» між браузером і мережею. Він перехоплює HTTP-запити, кешує відповіді і дозволяє працювати офлайн. Приклади: PWA-застосунки, push-сповіщення, фонові синхронізації. ```javascript // service-worker.js self.addEventListener('fetch', (event) => { event.respondWith( caches.match(event.request).then((cached) => { return cached || fetch(event.request); }) ); }); ``` Це означає: якщо є закешована відповідь, віддати її, інакше завантажити з мережі. #### Приклад «паралельних» обчислень ```javascript const workers = Array.from({ length: 4 }, () => new Worker('calc.js')); let completed = 0; let result = 0; workers.forEach((w, i) => { w.postMessage(i); w.onmessage = (e) => { result += e.data; if (++completed === 4) console.log('Done:', result); }; }); ``` Так можна розподілити обчислення між кількома потоками, це «псевдопаралелізм». ### Коли варто використовувати Web Workers | Сценарій | Чому корисно | | --- | --- | | Складні обчислення | парсинг JSON, криптографія, машинне навчання | | Обробка великих даних | фільтрація та агрегація масивів, обробка CSV | | Робота із зображеннями | стиснення, фільтри, генерація мініатюр | | Ігри та анімація | розрахунки фізики без лагів інтерфейсу | | WebSocket плюс аналіз даних | потокова обробка | Проста аналогія: > Уявіть, що браузер це кухня. Головний потік (основний JS) це кухар, який готує страву і обслуговує гостей. Web Worker це помічник на іншій кухні, який нарізає овочі. Кухар дає завдання, помічник виконує його у фоні і повертає результат. Ніхто нікому не заважає. Підсумок: | Компонент | Що робить | | --- | --- | | **Web Worker** | Окремий потік для виконання коду | | **Головна перевага** | Не блокує UI | | **Обмін даними** | Через `postMessage` / `onmessage` | | **Обмеження** | Немає доступу до DOM, `window`, `document` | | **Типи** | Dedicated, Shared, Service Worker | | **Основні застосування** | Фонові обчислення, кеш, офлайн-режим, синхронізація | ### Типові помилки - Звертатися до `document` чи `window` усередині воркера. Їх там немає, потрібні дані треба передати повідомленням. - Чекати, що об'єкт передасться за посиланням. Дані копіюються через structured clone, тож великі масиви краще віддавати як Transferable (`ArrayBuffer`), інакше копіювання само по собі стане вузьким місцем. - Передавати у `postMessage` функції, DOM-вузли або класи з методами. Structured clone їх не підтримує і кине помилку. - Створювати новий воркер на кожен дрібний виклик. Запуск потоку коштує часу і пам'яті, воркери варто перевикористовувати або тримати їх пул. - Плутати Web Worker і Service Worker. Перший для обчислень, другий для перехоплення мережевих запитів і офлайн-режиму. - Забувати `worker.terminate()`. Воркер живе, доки його явно не зупинили або доки відкрита сторінка.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.