Structured Concurrency

Binding a concurrent operation's lifetime to its parent's, so cancelling the parent explicitly propagates to every child it started.

Purpose

Structured concurrency means a concurrent operation’s children never outlive their parent — when the parent is cancelled or completes, every child operation is cancelled or awaited too, with nothing left running independently and unaccounted for.

Example

async function processAll(items, signal) {
  const controller = new AbortController();
  signal.addEventListener('abort', () => controller.abort()); // parent cancellation propagates

  try {
    await Promise.all(items.map((item) => processItem(item, controller.signal)));
  } finally {
    controller.abort(); // no child outlives this function, success or failure
  }
}

Behavior notes

  • Cancellation does not propagate automatically in JavaScript — it requires explicit wiring, most often a child AbortController whose signal aborts when the parent’s does.
  • Promise.all itself provides a related but distinct guarantee: it settles once all promises settle, but doesn’t cancel the others if one rejects — only explicit AbortController wiring does that.
  • The finally block above ensures cleanup happens on every exit path (success, error, or external cancellation) — a common structured-concurrency idiom.

Common mistakes

  • Assuming cancelling an outer operation automatically cancels whatever async work it started internally — without explicit signal propagation, “cancelled” children keep running to completion, wasting work and potentially mutating state the caller believed was abandoned.
  • Creating child operations without ever wiring their cancellation to the parent at all, leaving no way to stop them once started.

Runtime notes

A coding discipline built on core AbortController/Promise behavior, applicable anywhere JavaScript’s async model is used.

Taught in these lessons

Related reference

Updated 2026-09-03