Model cancellation like AbortController
When a modal closes or a route changes, the work it started is no longer wanted. AbortController is how the platform expresses that: a controller holds the abort() method, and the passive signal is handed to whatever should stop. Building it yourself makes the contract concrete.
Implement two things. First, createCanceller() returns an object { signal, cancel }. signal.cancelled starts as false and signal.reason starts as null. Calling cancel(reason) sets cancelled to true and stores reason, defaulting to the string "Cancelled", and synchronously calls every listener registered with signal.onCancel(listener), passing the reason. Cancelling twice does nothing the second time: the first reason is kept and listeners are not called again. A listener registered after cancellation is called immediately with the stored reason. Second, delay(ms, signal) returns a promise that resolves with undefined after ms milliseconds, but rejects with new Error(signal.reason) as soon as the signal is cancelled, clearing its timer. If the signal is already cancelled when delay is called, it rejects straight away. signal may be omitted, in which case the delay simply resolves.
Arguments
msnumberdelay's wait time in milliseconds.signal{ cancelled: boolean, reason: any, onCancel: Function } | undefined- Optional signal from
createCanceller(). Rejects the delay when cancelled.
Returns
Promise<void> — delay resolves after ms or rejects with Error(signal.reason) if the signal is cancelled. createCanceller() returns { signal, cancel } synchronously (not a promise).
Examples
const { signal, cancel } = createCanceller();
const message = delay(500, signal).then(() => "waited", (e) => e.message);
setTimeout(() => cancel("user left"), 10);
// await message === "user left" — rejected early, timer clearedA cancel aborts a pending delay almost immediately.
const { signal, cancel } = createCanceller();
cancel(); // defaults the reason to "Cancelled"
let received = "not called";
signal.onCancel((reason) => { received = reason; });
// received === "Cancelled" — late listener fires immediatelyListeners registered after cancellation are invoked right away.
What it has to do
- Start with
cancelledfalse andreasonnull. - Default the cancel reason to the string
Cancelled. - Call
onCancellisteners synchronously, once, in registration order. - Call a listener registered after cancellation immediately.
- Have
delayreject with anErrorcarrying the reason, both when cancelled while waiting and when already cancelled.
Notes
- Call
onCancellisteners synchronously insidecancelso adelaylistener can clear its timer before the current tick ends. - A listener registered after cancellation must fire immediately with the stored reason — otherwise late subscribers silently miss the event.
Stuck? The javascript course covers everything this challenge needs.
- 1.starts uncancelled with a null reason
- 2.notifies listeners once and keeps the first reason
- 3.defaults the reason and fires late listeners immediately
- 4.delay rejects as soon as the signal is cancelled
- 5.delay resolves normally and rejects instantly when already cancelled
These assertions run in your browser the moment you hit Run. Pass all of them to claim the XP.
Discussion
Sign in to postNo comments yet. Be the first to say something.