Skip to solution
hardDSA

How does `Atomics.waitAsync()` enable non-blocking waits on SharedArrayBuffer?

1.1k views
01

Understand the problem

Question presented to candidate: "Atomics.wait() blocks the calling thread until another thread calls Atomics.notify() on the same location. Why can that be a problem, and how does Atomics.waitAsync() solve it? Walk through what its return value actually looks like, and what happens on Node's main thread specifically versus a browser's main thread."

What a strong answer should cover:

  • Atomics.wait(typedArray, index, value, timeout) blocks the calling thread's execution entirely until another thread calls Atomics.notify() on that exact index, or the timeout elapses — nothing else on that thread runs while blocked, including timers and I/O callbacks.
  • Atomics.waitAsync() returns synchronously and immediately, shaped { async: boolean, value }. If the current value already differs from the expected one, it returns { async: false, value: "not-equal" } with no promise involved. Otherwise it returns { async: true, value: aPromise } that resolves to "ok" or "timed-out".
  • In BROWSERS, Atomics.wait() throws a TypeError on the main/UI thread specifically — it is only legal on a Worker there, since blocking the UI thread would freeze the page. Node.js has no such restriction: Node's "main thread" is not a UI thread, so Atomics.wait() is legal there and simply blocks it — verified directly, not assumed.
  • waitAsync()'s pending promise does not block the event loop while pending — other code, timers, and I/O keep running normally, verified by a real interleaved setTimeout that fires before the promise resolves.
  • SharedArrayBuffer plus Atomics is the actual low-level primitive underneath higher-level constructs like WebAssembly threads and hand-rolled worker pools that need to coordinate without message-passing overhead.

Clarifying questions expected:

  • "Does this run in a browser or in Node.js?" — the main-thread-blocking restriction on Atomics.wait() is browser-specific, not a JavaScript-spec-wide rule, and answering as if it always throws is a common but real mistake worth naming explicitly.
  • "Is cross-origin isolation (COOP/COEP headers) set up?" — SharedArrayBuffer is disabled by default in browsers without those headers, which silently makes this whole API surface unavailable.

Code / implementation expected: Yes — a real, non-blocking waitAsync() call verified to return immediately, plus a real cross-thread worker_threads example proving the promise resolves only after a genuine Atomics.notify() from another thread.

atomicssharedarraybufferconcurrency
02

Attempt it yourself

Sketch your approach before reading the solution — that's what interviews test.

Nudge consolestandby

Stuck? Beam a request up — the console returns a conceptual nudge that guides your logic without spoiling the implementation.

03

Study the solution

Target Audience: Engineers preparing for JavaScript concurrency and SharedArrayBuffer interview questions. Difficulty: Hard

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:. Every result shown below is real, captured output from ac

Solution ready — 2 min read

Classified // press E to declassify

04

Run the code

JSNon-blocking waitAsync() with a same-thread simulated notifier (works anywhere, including this playground) (run directly)
Reference: genuine cross-thread coordination via node:worker_threads, a real second thread calling Atomics.notify() (run with: node file.js -- worker_threads is Node-only, not available in the browser playground)
import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads";

if (isMainThread) {
  const sab = new SharedArrayBuffer(4);
  const i32 = new Int32Array(sab);
  i32[0] = 0;

  const t0 = Date.now();
  const worker = new Worker(new URL(import.meta.url), { workerData: { sab } });

  console.log("[main] calling Atomics.waitAsync -- must NOT block");
  const { async, value } = Atomics.waitAsync(i32, 0, 0, 5000);
  console.log("[main] waitAsync returned immediately, async:", async);

  value.then((result) => {
    console.log(`[main] promise resolved with "${result}" after ${Date.now() - t0}ms`);
    worker.terminate();
  });

  console.log("[main] this line runs right after waitAsync");
} else {
  const { sab } = workerData;
  const i32 = new Int32Array(sab);
  const start = Date.now();
  while (Date.now() - start < 300) { /* real work, inside the WORKER only */ }
  Atomics.store(i32, 0, 1);
  const woken = Atomics.notify(i32, 0, 1);
  console.log("[worker] Atomics.notify() woke", woken, "waiter(s)");
}
05

Join the discussion

Discussion (0)

Sign in to join the discussion.

No responses yet. Be the first to share what you think.

Transmission complete // awaiting log

KEEP THE
STREAK ALIVE.

Dossier 124 of 165 decoded in the JavaScript track. One more won't hurt.

Back to track