Parallel JavaScript and SharedArrayBuffer isolation
Exploring parallel processing in JavaScript using SharedArrayBuffer and the security considerations of cross-origin isolation
Shared memory in the browser has travelled a cautious path since the 2018 Spectre disclosures, yet in mid-2025 JavaScript developers can rely on SharedArrayBuffer
again, provided they host their pages in a cross-origin isolated context and coordinate threads with the Atomics API. This article traces the security story that led to the current requirements, explains how the COOP and COEP response headers create a safe boundary, and shows how shared memory unlocks true parallel work with Web Workers and WebAssembly. Each section pairs the theory with code snippets and measurable effects so that you can judge whether the added headers and deployment changes are worth the gain.
The road back from Spectre
When Spectre attacks proved that speculative execution could leak data through timing side channels, browsers removed high-resolution timers and disabled SharedArrayBuffer
, cutting off shared memory for Web Workers. A multi-vendor task force then defined cross-origin isolation, a state that separates a document from other browsing contexts and blocks unvetted resources, restoring the safety needed for precise timers and shared buffers.
Cross-origin isolation in practice
The two required headers
To reach self.crossOriginIsolated === true
, the server must send
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
The opener policy keeps the top-level window in its own browsing context group, preventing it from sharing a process with unrelated pages. The embedder policy forces every subresource to grant permission through either CORS or a Cross-Origin-Resource-Policy
header, closing the path for untrusted scripts or iframes.
Verifying isolation
The global crossOriginIsolated
property appears on Window
and WorkerGlobalScope
objects; a true
value confirms that the browser has applied the isolation rules. Chrome DevTools lists the state under Security & Isolation so that you can check the flag without code.
SharedArrayBuffer and Atomics
A SharedArrayBuffer
creates a block of binary data visible to every worker that receives a reference through postMessage
. The buffer itself is shared, yet threads must guard reads and writes with Atomics
operations to avoid data races. The API offers low-level tools such as Atomics.store
, Atomics.load
, Atomics.add
, and the wait
/ notify
pair that implements blocking queues.
Example
// main.js
if (crossOriginIsolated) {
const sab = new SharedArrayBuffer(4)
const view = new Int32Array(sab)
const worker = new Worker('worker.js')
worker.postMessage(sab)
Atomics.store(view, 0, 42)
Atomics.notify(view, 0, 1)
}
// worker.js
onmessage = (e) => {
const view = new Int32Array(e.data)
Atomics.wait(view, 0, 0)
console.log('value:', Atomics.load(view, 0))
}
Browser support in 2025
- Firefox enabled
SharedArrayBuffer
for cross-origin isolated pages in version 79 and has followed the standard ever since. - Chrome gated the feature behind isolation on desktop from version 92 and extended the origin trial for sites that still need time to migrate.
- Safari shipped the new model in Safari 17 and continues to refine it in Safari 18, though some AudioWorklet cases still appear in WebKit issue trackers.
- Edge inherits the Chromium behaviour, so the same headers apply.
Performance gains and limits
Benchmarks that push computation into workers show speed-ups that range from twofold improvements in image processing to near-native throughput when WebAssembly threads map onto shared memory. The gains start reducing if the workload is I/O bound or if the workers compete for a single core. Remember that shared memory helps only when the cost of serialising messages is higher than the cost of locking and waiting on atomics.
Common deployment hurdles
- Third-party embeds may fail because COEP blocks any resource that lacks a compatible CORS or CORP header, so audit ads, analytics, and legacy widgets early.
- OAuth and payment popups rely on
window.opener
, which COOP severs; thesame-origin-allow-popups
variant softens that break but still keeps isolation. - Credentialless mode in COEP allows you to import public resources without CORS but is only stable in Chrome and Edge at the moment.
When shared memory pays off
Choose SharedArrayBuffer
for real-time simulation, large data transforms, or WebAssembly ports that need pthreads. Pair it with a pool of workers and measured atomic operations, and you will see smoother frames and lower CPU spikes compared with the copy-based alternative. For lightweight tasks that wake once every few milliseconds, simpler message passing keeps code clearer and avoids the header work.
Closing thoughts
Cross-origin isolation resurrected parallel JavaScript without reopening the Spectre risks. Two headers, a runtime check, and careful worker design give you direct shared memory and the performance headroom that comes with it. Adopt the pattern where the payoff is clear, budget time for header audits, and you will join the growing number of sites that exploit true multithreading while staying inside the browser's modern safety model.