Cancellation in modern JavaScript is one signal — AbortSignal — wired through fetch, addEventListener, streams, and timers. Pick a strategy (timeout, manual abort, race), wire up signals, and either run a live fetch() against a public endpoint or simulate a slow async task. The generated code uses AbortSignal.timeout() and AbortSignal.any() when they apply.
https://httpbin.org/delay/3 (3s) or https://httpbin.org/delay/1 (1s) to see timeouts succeed vs fail.AbortSignal.any(). Whichever fires first wins, and reason tells you which.AbortController: all modern browsers + Node 15+. AbortSignal.timeout(): Chrome 103+, Safari 15.4+, Firefox 100+. AbortSignal.any(): Chrome 116+, Safari 17.4+, Firefox 124+ (early 2024).
const ctrl = new AbortController(); fetch(url, { signal: ctrl.signal }); ctrl.abort(reason). The optional reason becomes signal.reason and the rejection value.fetch(url, { signal: AbortSignal.timeout(2000) }) — no controller bookkeeping, no leaked timer.AbortSignal.any([userCancel.signal, AbortSignal.timeout(5000)]) aborts on the first source to fire.AbortController in the effect, pass signal to async work, and call ctrl.abort() in the cleanup return.DOMException named "AbortError". Check err.name === 'AbortError' or compare signal.reason.addEventListener('scroll', fn, { signal }) auto-removes the listener when the signal aborts. Same with streams, observers, and many Node APIs.