cancel()
Cancel all running and future executions of the task.
Syntax
typescript
task.cancel(): voidParameters
None.
Return Value
void
Description
The cancel() method aborts all running and future executions of the task. When called:
- Aborts the internal AbortSignal
- Executes all registered task-level
onCancel()callbacks - Cancels all Futurables created by
run()that haven't completed yet - Prevents new executions from starting (they will remain pending)
This method is idempotent - calling it multiple times has no additional effect.
Examples
Basic Cancellation
typescript
const task = FuturableTask.of(() => {
console.log('Starting...');
return longRunningOperation();
});
const execution = task.run();
// Cancel the task
task.cancel();
// The execution will be cancelledCancel Before Execution
typescript
const task = FuturableTask.of(() => expensiveOperation());
// Cancel before running
task.cancel();
// This won't execute
const result = task.run(); // Will remain pendingCancel During Execution
typescript
const task = FuturableTask.of((resolve, reject, { signal }) => {
const interval = setInterval(() => {
if (signal.aborted) {
clearInterval(interval);
return;
}
console.log('Working...');
}, 100);
});
const execution = task.run();
// Cancel after 500ms
setTimeout(() => task.cancel(), 500);Cancel Multiple Executions
typescript
const task = FuturableTask.of(() => fetchData());
// Start multiple executions
const run1 = task.run();
const run2 = task.run();
const run3 = task.run();
// Cancel all at once
task.cancel();
// All three executions are cancelledWith Cleanup Callbacks
typescript
const task = FuturableTask
.of(() => {
const resource = allocateResource();
return processResource(resource);
})
.onCancel(() => {
console.log('Cleaning up resources');
cleanupResources();
});
task.cancel(); // Logs: "Cleaning up resources"React Component Cleanup
typescript
function DataFetcher({ id }) {
const [data, setData] = useState(null);
useEffect(() => {
const task = FuturableTask
.fetch(`/api/data/${id}`)
.map(res => res.json());
task.run().then(setData);
// Cancel on unmount or id change
return () => task.cancel();
}, [id]);
return <div>{data?.name}</div>;
}Timeout Pattern
typescript
const task = FuturableTask.of(() => slowOperation());
// Auto-cancel after timeout
setTimeout(() => task.cancel(), 5000);
try {
const result = await task.run();
} catch (error) {
console.log('Operation timed out or cancelled');
}User-Initiated Cancellation
typescript
let currentTask: FuturableTask<any> | null = null;
function startOperation() {
// Cancel previous operation if exists
if (currentTask) {
currentTask.cancel();
}
currentTask = FuturableTask.of(() => performOperation());
return currentTask.run();
}
function cancelOperation() {
if (currentTask) {
currentTask.cancel();
currentTask = null;
}
}Behavior Details
Idempotent
typescript
const task = FuturableTask.of(() => work());
task.cancel();
task.cancel(); // No effect
task.cancel(); // No effectSignal State
typescript
const task = FuturableTask.of(() => work());
console.log(task.signal.aborted); // false
task.cancel();
console.log(task.signal.aborted); // truePending Executions
typescript
const task = FuturableTask.of(() => work());
task.cancel();
// This will create a Futurable but won't execute
const execution = task.run();
// The execution remains pending indefinitely
await execution; // Never resolves or rejectsCleanup Order
typescript
const task = FuturableTask
.of(() => work())
.onCancel(() => console.log('Cleanup 1'))
.onCancel(() => console.log('Cleanup 2'))
.onCancel(() => console.log('Cleanup 3'));
task.cancel();
// Logs in order:
// "Cleanup 1"
// "Cleanup 2"
// "Cleanup 3"Common Patterns
Cancellable Search
typescript
class SearchManager {
private currentSearch: FuturableTask<any> | null = null;
search(query: string) {
// Cancel previous search
if (this.currentSearch) {
this.currentSearch.cancel();
}
this.currentSearch = FuturableTask
.fetch(`/api/search?q=${query}`)
.map(res => res.json());
return this.currentSearch.run();
}
clearSearch() {
if (this.currentSearch) {
this.currentSearch.cancel();
this.currentSearch = null;
}
}
}Request Deduplication
typescript
const cache = new Map<string, FuturableTask<any>>();
function fetchWithDedup(url: string) {
if (cache.has(url)) {
const existing = cache.get(url)!;
return existing.run();
}
const task = FuturableTask.fetch(url).map(r => r.json());
cache.set(url, task);
return task.run();
}
function invalidateCache(url: string) {
const task = cache.get(url);
if (task) {
task.cancel();
cache.delete(url);
}
}Cancellation Token
typescript
class CancellationToken {
private tasks: Set<FuturableTask<any>> = new Set();
register<T>(task: FuturableTask<T>): FuturableTask<T> {
this.tasks.add(task);
return task;
}
cancelAll() {
this.tasks.forEach(task => task.cancel());
this.tasks.clear();
}
}
const token = new CancellationToken();
token.register(FuturableTask.of(() => op1())).run();
token.register(FuturableTask.of(() => op2())).run();
token.register(FuturableTask.of(() => op3())).run();
// Cancel all operations
token.cancelAll();Difference from Futurable.cancel()
typescript
// Futurable: cancels a specific execution
const futurable = Futurable.fetch('/api/data');
futurable.cancel(); // Only this execution
// FuturableTask: cancels all executions
const task = FuturableTask.fetch('/api/data');
const run1 = task.run();
const run2 = task.run();
task.cancel(); // Both run1 and run2 are cancelledBest Practices
1. Always Cleanup Resources
typescript
const task = FuturableTask
.of(() => {
const ws = new WebSocket(url);
return listenToSocket(ws);
})
.onCancel(() => {
ws.close(); // Always cleanup
});2. Cancel on Component Unmount
typescript
useEffect(() => {
const task = FuturableTask.of(() => fetchData());
task.run().then(setData);
return () => task.cancel(); // Cleanup
}, []);3. Cancel Previous Operations
typescript
let currentTask: FuturableTask<any> | null = null;
function startNew() {
currentTask?.cancel(); // Cancel old
currentTask = FuturableTask.of(() => newOperation());
return currentTask.run();
}4. Use with Timeouts
typescript
const task = FuturableTask.of(() => operation());
const timeout = setTimeout(() => task.cancel(), 5000);
try {
const result = await task.run();
clearTimeout(timeout);
} catch (error) {
// Handle cancellation or error
}Notes
- Calling
cancel()multiple times is safe (idempotent) - Cancelled tasks cannot be "uncancelled"
- Executions started after cancellation will remain pending
- All
onCancel()callbacks are executed when cancelled - The internal signal is aborted permanently
- Does not throw errors - cancellation is silent
See Also
- onCancel() - Register cancellation callbacks
- run() - Execute the task
- signal - Access the abort signal
- Constructor - Create tasks
