Abort and timeouts

AbortController

AbortController ships as a global since Node 15, so no import is needed. Create one controller per task and pass its signal down. Calling abort tells every listener that the work is no longer wanted.

const ctrl = new AbortController(); ctrl.signal.addEventListener("abort", () => { console.log("aborted"); }); ctrl.abort();

Abort after ms

Pair the controller with a timer to bound the wait. Start the timer next to the work and call abort when it fires. The worker sees the abort event and can stop early.

const ctrl2 = new AbortController(); const timer = setTimeout(() => { ctrl2.abort(); }, 1000); ctrl2.signal.addEventListener("abort", () => { console.log("timed out"); });

Cancel without fetch

Node 16 has no global fetch, but https requests accept the same signal. Pass the signal in the request options. Destroy the request on abort so sockets do not linger.

import * as https from "https"; const ctrl3 = new AbortController(); const req = https.get("https://example.com", { signal: ctrl3.signal }); ctrl3.signal.addEventListener("abort", () => { req.destroy(); });

Clean timers

Always clear the timeout once the work settles. A live timer keeps the process awake and fires a late abort by surprise. Put clearTimeout in a finally block so both success and failure clean up.

async function guarded(work: Promise<string>): Promise<string> { const ctrl = new AbortController(); const timer = setTimeout(() => ctrl.abort(), 1000); try { return await work; } finally { clearTimeout(timer); } }

Next: Async error handling

Article author: Arthur Isaev

Banner image