JavaScript
advanced
#javascript#web-workers#concurrency

Parallel JavaScript and SharedArrayBuffer isolation

Exploring parallel processing in JavaScript using SharedArrayBuffer and the security considerations of cross-origin isolation

July 2, 2025
5 min read
Share this article:

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

js
// 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)
}
js
// 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; the same-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.