Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що робить postMessage() між потоками?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`postMessage()`** - це метод, який дозволяє надіслати повідомлення з одного контексту в інший (наприклад, з основного потоку у Web Worker або навпаки). **Ключове:** він не виконує прямого доступу до пам'яті, а передає копію даних асинхронно через механізм message passing (обмін повідомленнями).Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що робить `postMessage()` > `postMessage()` - це метод, який дозволяє **надіслати повідомлення з одного контексту в інший** > (наприклад, з основного потоку у Web Worker або навпаки). Він **не виконує прямого доступу до пам'яті**, а передає **копію** даних - асинхронно, через механізм **message passing** (обмін повідомленнями). ## Як це виглядає з Web Worker ### Приклад ```javascript // main.js const worker = new Worker('worker.js'); // Надсилаємо повідомлення воркеру worker.postMessage({ task: 'sum', a: 5, b: 7 }); // Отримуємо відповідь worker.onmessage = (event) => { console.log('Відповідь від воркера:', event.data); }; ``` ```javascript // worker.js onmessage = (event) => { const { task, a, b } = event.data; if (task === 'sum') { postMessage(a + b); // надсилаємо результат назад } }; ``` **Що відбувається:** 1. Основний потік викликає `worker.postMessage(...)`; 2. Повідомлення серіалізується і поміщається в **чергу повідомлень** воркера; 3. У воркері спрацьовує подія `onmessage`; 4. Воркер виконує обробку і відповідає через `postMessage()`; 5. Основний потік ловить цю подію через `onmessage`. Усе це відбувається **асинхронно** - JavaScript **не чекає**, поки воркер відповість. ## Що саме передається Можна передавати: - Примітиви (`string`, `number`, `boolean`, `null`, `undefined`); - Об'єкти (JSON-сумісні); - `ArrayBuffer`, `Blob`, `File`, `ImageBitmap`; - **Transferable об'єкти** - передаються **без копіювання**. ## Що таке *Transferable Objects* Зазвичай дані **копіюються** під час передачі між потоками (через structured clone). Але для великих бінарних даних це дорого. > **Transferable Objects** (наприклад, `ArrayBuffer`) можна "передати за посиланням" > - без копіювання, просто **передавши володіння**. ### Приклад: ```javascript const buffer = new ArrayBuffer(1024); worker.postMessage(buffer, [buffer]); // передаємо як transferable ``` Після передачі `buffer` в основному потоці стає **невалідним** (тому що "володіння" перейшло воркеру). Це **у 10-100 разів швидше** при передачі великих даних. ## Що повертає `postMessage()` Нічого. Він просто ставить повідомлення в чергу іншої сторони. Отримувач зловить його через подію `message`: ```javascript worker.onmessage = (event) => { console.log(event.data); }; ``` ## Взаємодія в обидва боки | Звідки | Метод | Слухач | |---|---|---| | Головний потік -> воркер | `worker.postMessage()` | `onmessage` у воркері | | Воркер -> головний потік | `postMessage()` | `worker.onmessage` | ## Приклад "луна" (echo worker) ```javascript // worker.js onmessage = (event) => { postMessage(`Луна: ${event.data}`); }; ``` ```javascript // main.js worker.postMessage('Привіт!'); worker.onmessage = (e) => console.log(e.data); // -> "Луна: Привіт!" ``` ## `postMessage()` не тільки для Web Workers Цей метод універсальний - він працює в різних контекстах браузера: | Де використовується | Приклад | |---|---| | **window -> iframe** | `iframe.contentWindow.postMessage(data, origin)` | | **iframe -> parent** | `window.parent.postMessage(data, origin)` | | **між вкладками** | `otherWindow.postMessage(data, origin)` | | **Service Worker <-> Main** | `navigator.serviceWorker.controller.postMessage(data)` | | **Web Worker <-> Main** | `worker.postMessage(data)` | ## Приклад: `window.postMessage()` між сторінками ```javascript // Сторінка А const popup = window.open('https://example.com/popup.html'); popup.postMessage('Привіт, сторінко Б!', 'https://example.com'); // Сторінка Б window.addEventListener('message', (event) => { if (event.origin === 'https://example.com') { console.log('Отримано повідомлення:', event.data); } }); ``` Дуже корисно для **безпечної взаємодії** між різними доменами (CORS-safe). ## Як це влаштовано під капотом 1. Коли викликається `postMessage()`, дані **серіалізуються** за допомогою Structured Clone Algorithm; 2. Копія даних поміщається в чергу отримувача; 3. Коли потік звільняється, браузер викликає обробник `onmessage(event)`; 4. Дані доступні в `event.data`. ## Що всередині `event` ```javascript onmessage = (event) => { console.log(event.data); // самі дані console.log(event.origin); // джерело (для вікон/iframe) console.log(event.ports); // MessagePort, якщо є console.log(event.source); // хто надіслав повідомлення }; ``` ## Проста аналогія Уяви, що `postMessage()` - це **поштова служба між офісами**. Кожен офіс (потік JS) працює **ізольовано**. Коли один хоче передати дані іншому, він кладе лист (повідомлення) у скриньку (`postMessage`). Інший офіс отримує лист, коли у нього є час (`onmessage`). ## Підсумок | Що робить | Пояснення | |---|---| | `postMessage()` | Надсилає повідомлення між потоками / контекстами | | **Працює асинхронно** | Не блокує код | | **Передає дані копією** | Через structured clone | | **Оптимізація** | Transferable об'єкти - без копіювання | | **Двосторонній зв'язок** | Обидва потоки можуть надсилати і приймати | | **Використовується де** | Web Workers, iframe, вікна, Service Workers |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.