Skip to main content

Що робить postMessage() між потоками?

Що робить 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 -> iframeiframe.contentWindow.postMessage(data, origin)
iframe -> parentwindow.parent.postMessage(data, origin)
між вкладкамиotherWindow.postMessage(data, origin)
Service Worker <-> Mainnavigator.serviceWorker.controller.postMessage(data)
Web Worker <-> Mainworker.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

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.