Що робить SharedArrayBuffer?
Що таке SharedArrayBuffer
SharedArrayBuffer - це спеціальний тип буфера, який:
- містить сирі двійкові дані (байти);
- може бути розділений між різними потоками (наприклад, Web Worker і основним потоком);
- дозволяє одночасно читати й писати в ту саму пам'ять;
- не копіює дані при передачі - передається посилання на ту саму ділянку пам'яті.
Відмінність від звичайного ArrayBuffer
| Властивість | ArrayBuffer | SharedArrayBuffer |
|---|---|---|
| Використовується ким | Одним потоком | Кількома потоками |
| При передачі воркеру | Копіюється або передається через transfer (стає недоступним у вихідному потоці) | Розділяється - обидва потоки бачать ту саму пам'ять |
| Можна використовувати Atomics | Ні | Так (для безпечної синхронізації) |
| Потокобезпека | Не потрібна | Потрібна (через Atomics) |
Приклад: спільний буфер між потоками
1. Основний потік (main.js)
// Створюємо спільний буфер на 4 байти (Int32 = 4 байти)
const sharedBuffer = new SharedArrayBuffer(4);
// Обгортаємо його в типізований масив
const sharedArray = new Int32Array(sharedBuffer);
sharedArray[0] = 0; // початкове значення
// Створюємо воркер і передаємо спільний буфер
const worker = new Worker('worker.js');
worker.postMessage(sharedBuffer);
// Очікуємо змін
setInterval(() => {
console.log('Main thread value:', sharedArray[0]);
}, 1000);2. Воркер (worker.js)
onmessage = (e) => {
const sharedArray = new Int32Array(e.data);
// Збільшуємо значення кожні 500 мс
setInterval(() => {
Atomics.add(sharedArray, 0, 1); // атомарне приростання
}, 500);
};Результат:
Main thread value: 0
Main thread value: 2
Main thread value: 4
Main thread value: 6
...SharedArrayBuffer забезпечує спільну пам'ять, а Atomics гарантує потокобезпеку (без гонок даних).
Навіщо потрібен Atomics
Оскільки кілька потоків можуть одночасно читати й записувати одну й ту саму комірку пам'яті, без синхронізації можуть виникати гонки (race conditions).
Для цього існує об'єкт Atomics, який надає атомарні операції:
| Метод | Що робить |
|---|---|
Atomics.add(typedArray, index, value) | Додає значення атомарно |
Atomics.sub() | Віднімає атомарно |
Atomics.and() / or() / xor() | Побітові атомарні операції |
Atomics.load() / Atomics.store() | Безпечне читання/запис |
Atomics.exchange() | Змінює значення і повертає старе |
Atomics.compareExchange() | Змінює, якщо поточне збігається з очікуваним |
Atomics.wait() / Atomics.notify() | Дозволяє "приспати" потік, поки значення не зміниться (лише у воркерах) |
Приклад: синхронізація за допомогою Atomics.wait / Atomics.notify
// main.js
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
const worker = new Worker('worker.js');
worker.postMessage(sharedBuffer);
// Через 2 секунди "розбудимо" воркер
setTimeout(() => {
console.log('Main: notify worker');
Atomics.store(sharedArray, 0, 1);
Atomics.notify(sharedArray, 0, 1);
}, 2000);// worker.js
onmessage = (e) => {
const sharedArray = new Int32Array(e.data);
console.log('Worker: waiting...');
Atomics.wait(sharedArray, 0, 0); // чекає, поки значення не зміниться
console.log('Worker: woken up, value:', sharedArray[0]);
};Тут воркер буквально "спить", поки основний потік не "розбудить" його. Це дає реальну багатопотоковість (координацію між потоками JS).
Де використовується SharedArrayBuffer
| Сценарій | Застосування |
|---|---|
| Web Workers | Передача великих даних без копіювання |
| Багатопотокові обчислення | Паралельна обробка матриць, графіки, фізики |
| Ігри та симуляції | Оновлення стану світу в кількох потоках |
| Machine Learning / WASM | TensorFlow.js, WebAssembly, OpenCV використовують SharedArrayBuffer |
| Обробка відео / аудіо | Спільне використання буферів між потоками |
| Шина обміну між воркерами | Миттєва передача даних без серіалізації JSON |
Безпека й обмеження (CORS / COOP / COEP)
Через ризики вразливостей Spectre браузери вмикають SharedArrayBuffer лише в ізольованих контекстах (Cross-Origin Isolation).
Щоб SharedArrayBuffer працював у браузері, потрібно виставити правильні заголовки:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corpІ переконатися, що всі ресурси (скрипти, воркери) також сумісні з цим режимом.
Приклад: увімкнення Cross-Origin Isolation
Для dev-сервера (наприклад, Vite чи Express):
app.use((req, res, next) => {
res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
next();
});Тепер браузер дозволить використовувати SharedArrayBuffer.
Підсумок
| Властивість | Опис |
|---|---|
| Що робить | Розділяє пам'ять між потоками без копіювання |
| Де працює | У Web Workers і Node.js (worker_threads) |
| Вимагає | Atomics для синхронізації |
| Безпека | Лише при увімкненому COOP/COEP |
| Типові сценарії | Паралельні обчислення, кеш, рендеринг, WebAssembly |
| Аналог у C/C++ | Спільна пам'ять (shared memory) між потоками |
Головна ідея:
SharedArrayBufferдає JavaScript можливість реального паралелізму
- кілька потоків можуть читати й писати в одну пам'ять одночасно, а
Atomicsпри цьому забезпечує коректність і синхронізацію.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.