Skip to content
Buy me a coffee

dispose & lifetimes

controller.dispose() releases what the controller holds:

  • the pending abortAfter timer, and
  • the listeners a linked controller put on its parents.

It does not abort. Like .NET’s CancellationTokenSource.Dispose, it is about resources, not about stopping work. Code waiting on the signal is not woken up.

const
const controller: EnhancedAbortController
controller
= new
new EnhancedAbortController(): EnhancedAbortController

An AbortController with .NET CancellationTokenSource features. It is an AbortController, and controller.signal is a real AbortSignal: pass it to fetch, AbortSignal.any, streams, timers and any other API that takes a signal.

@example

const controller = new EnhancedAbortController().abortAfter(TimeSpan.fromSeconds(5));
const response = await fetch(url, { signal: controller.signal });

EnhancedAbortController
().
EnhancedAbortController.abortAfter(delay: Delay): EnhancedAbortController

Aborts after delay, like .NET's CancelAfter: calling it again replaces the previous schedule, and Infinity / -1 / TimeSpan.infinite cancel it. The reason is a DOMException named TimeoutError, as with AbortSignal.timeout. The timer never keeps the process alive, and delays longer than 24.8 days work. Does nothing once aborted. Returns the controller, for chaining.

@throws ― RangeError for NaN, negative (other than -1) or non-numeric delays.

@throws ― Error if the controller was disposed.

abortAfter
(100);
const controller: EnhancedAbortController
controller
.
EnhancedAbortController.dispose(): void

Releases what the controller holds: the scheduled abort and the listeners it put on linked parent signals. It does not abort (like .NET's Dispose); call abort() first if work should stop. abort() still works afterwards. Safe to call more than once; supports using.

dispose
();
const controller: EnhancedAbortController
controller
.
EnhancedAbortController.signal: EnhancedSignal

The controller's signal: a real AbortSignal, always the same object.

signal
.
AbortSignal.aborted: boolean

The aborted read-only property returns a value that indicates whether the asynchronous operations the signal is communicating with are aborted (true) or not (false).

MDN Reference

aborted
; // false, and the 100 ms deadline will never fire
const controller: EnhancedAbortController
controller
.
EnhancedAbortController.isDisposed: boolean

True after

dispose

.

isDisposed
; // true
const controller: EnhancedAbortController
controller
.
AbortController.abort(reason?: any): void

The abort() method of the AbortController interface aborts an asynchronous operation before it has completed.

MDN Reference

abort
('late'); // still works after dispose
// controller.abortAfter(10); // throws: a disposed controller can't schedule
After dispose()
abort(reason) Works.
abortAfter(delay) Throws Error (a RangeError first if the delay is invalid).
dispose() again No-op.
Signal listeners, register callbacks Untouched: they still run if you abort() later.

EnhancedAbortController implements Disposable, so using disposes it at the end of the block, however the block exits:

async function
function withDeadline(): Promise<string>
withDeadline
() {
using
using controller: EnhancedAbortController
controller
= new
new EnhancedAbortController(): EnhancedAbortController

An AbortController with .NET CancellationTokenSource features. It is an AbortController, and controller.signal is a real AbortSignal: pass it to fetch, AbortSignal.any, streams, timers and any other API that takes a signal.

@example

const controller = new EnhancedAbortController().abortAfter(TimeSpan.fromSeconds(5));
const response = await fetch(url, { signal: controller.signal });

EnhancedAbortController
().
EnhancedAbortController.abortAfter(delay: Delay): EnhancedAbortController

Aborts after delay, like .NET's CancelAfter: calling it again replaces the previous schedule, and Infinity / -1 / TimeSpan.infinite cancel it. The reason is a DOMException named TimeoutError, as with AbortSignal.timeout. The timer never keeps the process alive, and delays longer than 24.8 days work. Does nothing once aborted. Returns the controller, for chaining.

@throws ― RangeError for NaN, negative (other than -1) or non-numeric delays.

@throws ― Error if the controller was disposed.

abortAfter
(
class TimeSpan

An immutable time interval, stored in milliseconds. Modeled on .NET's TimeSpan.

@example

controller.abortAfter(TimeSpan.fromSeconds(30));
TimeSpan.fromMinutes(1).add(TimeSpan.fromSeconds(30)).totalSeconds; // 90

TimeSpan
.
TimeSpan.fromSeconds(seconds: number): TimeSpan
fromSeconds
(5));
return await
function work(signal: AbortSignal): Promise<string>
work
(
using controller: EnhancedAbortController
controller
.
EnhancedAbortController.signal: EnhancedSignal

The controller's signal: a real AbortSignal, always the same object.

signal
);
} // finished in 1 s? The 5 s timer is cleared here.

Keep the await in return await: without it the function returns the pending promise, using disposes at once, and the deadline is gone while the work still runs.

Without using:

const
const controller: EnhancedAbortController
controller
= new
new EnhancedAbortController(): EnhancedAbortController

An AbortController with .NET CancellationTokenSource features. It is an AbortController, and controller.signal is a real AbortSignal: pass it to fetch, AbortSignal.any, streams, timers and any other API that takes a signal.

@example

const controller = new EnhancedAbortController().abortAfter(TimeSpan.fromSeconds(5));
const response = await fetch(url, { signal: controller.signal });

EnhancedAbortController
().
EnhancedAbortController.abortAfter(delay: Delay): EnhancedAbortController

Aborts after delay, like .NET's CancelAfter: calling it again replaces the previous schedule, and Infinity / -1 / TimeSpan.infinite cancel it. The reason is a DOMException named TimeoutError, as with AbortSignal.timeout. The timer never keeps the process alive, and delays longer than 24.8 days work. Does nothing once aborted. Returns the controller, for chaining.

@throws ― RangeError for NaN, negative (other than -1) or non-numeric delays.

@throws ― Error if the controller was disposed.

abortAfter
(5000);
try {
await
function work(signal: AbortSignal): Promise<string>
work
(
const controller: EnhancedAbortController
controller
.
EnhancedAbortController.signal: EnhancedSignal

The controller's signal: a real AbortSignal, always the same object.

signal
);
} finally {
const controller: EnhancedAbortController
controller
.
EnhancedAbortController.dispose(): void

Releases what the controller holds: the scheduled abort and the listeners it put on linked parent signals. It does not abort (like .NET's Dispose); call abort() first if work should stop. abort() still works afterwards. Safe to call more than once; supports using.

dispose
();
}
You want Call
Stop the work abort()
The work finished; clean up dispose() (or using)
Stop the work and clean up abort(). An abort already releases the timer and the parent links; dispose() afterwards is harmless.

register() returns an AbortRegistration, which is disposable the same way: unregister(), dispose() or using.