Constructor
Create a new FuturableTask instance.
Syntax
typescript
new FuturableTask<T>(
executor: FuturableExecutor<T>,
externalSignal?: AbortSignal
)Parameters
executor
A function that defines the task's computation. Unlike Futurable, this function is not executed until .run() is called.
typescript
type FuturableExecutor<T> = (
resolve: (value: T | FuturableLike<T> | PromiseLike<T>) => void,
reject: (reason?: any) => void,
utils: FuturableUtils<T>
) => voidThe executor receives three parameters:
resolve: Function to fulfill the task with a valuereject: Function to reject the task with a reasonutils: Object containing utility methods and the abort signal
externalSignal (optional)
An external AbortSignal to control the task's cancellation. If provided, the task will be cancelled when this signal is aborted.
Return Value
A new FuturableTask<T> instance.
Description
The FuturableTask constructor creates a lazy async computation. Unlike Futurable, creating a FuturableTask does not execute the executor function. Execution only happens when you call .run().
Key Characteristics
- Lazy Evaluation: The executor is not called until
.run()is invoked - Reusable: Can be run multiple times, each execution is independent
- Cancellable: Can be cancelled before or during execution
- Composable: Can be transformed and chained before execution
Examples
Basic Usage
typescript
import { FuturableTask } from '@ndriadev/futurable';
// Creating the task doesn't execute it
const task = new FuturableTask((resolve, reject) => {
console.log('Executing!');
setTimeout(() => resolve('Done!'), 1000);
});
// Nothing logged yet
// Execute when ready
const result = await task.run(); // Logs: "Executing!"
console.log(result); // "Done!"With Cancellation Support
typescript
const task = new FuturableTask((resolve, reject, { signal, onCancel }) => {
const timeoutId = setTimeout(() => {
resolve('Completed');
}, 5000);
// Register cleanup
onCancel(() => {
console.log('Cleaning up...');
clearTimeout(timeoutId);
});
// Or use signal directly
signal.addEventListener('abort', () => {
clearTimeout(timeoutId);
reject(new Error('Cancelled'));
});
});
// Cancel before running
task.cancel();
await task.run(); // Won't execute
// Or cancel during execution
const execution = task.run();
setTimeout(() => task.cancel(), 1000);With External AbortSignal
typescript
const controller = new AbortController();
const task = new FuturableTask(
(resolve, reject) => {
setTimeout(() => resolve('Done'), 1000);
},
controller.signal // External signal
);
// Cancel via external controller
controller.abort();Async Executor
typescript
const task = new FuturableTask(async (resolve, reject, { signal }) => {
try {
const response = await fetch('https://api.example.com/data', { signal });
const data = await response.json();
resolve(data);
} catch (error) {
reject(error);
}
});Using Utils Methods
typescript
const task = new FuturableTask(async (resolve, reject, utils) => {
try {
// Wait 1 second
await utils.sleep(1000);
// Make a fetch request (automatically cancelled if task is cancelled)
const response = await utils.fetch('https://api.example.com/data');
const data = await response.json();
resolve(data);
} catch (error) {
reject(error);
}
});With Cleanup Logic
typescript
const task = new FuturableTask((resolve, reject, { onCancel }) => {
const ws = new WebSocket('wss://example.com');
ws.onmessage = (event) => {
resolve(event.data);
};
ws.onerror = (error) => {
reject(error);
};
// Cleanup is called on cancellation
onCancel(() => {
ws.close();
});
});
// Cleanup runs when cancelled
task.cancel();Alternative Constructors
FuturableTask.of()
Create a task from a function (recommended):
typescript
const task = FuturableTask.of(() => {
return expensiveOperation();
});
// With async function
const asyncTask = FuturableTask.of(async () => {
const res = await fetch('/api/data');
return res.json();
});FuturableTask.resolve()
Create an immediately successful task:
typescript
const task = FuturableTask.resolve(42);
await task.run(); // 42FuturableTask.reject()
Create an immediately failed task:
typescript
const task = FuturableTask.reject(new Error('Failed'));
await task.run(); // Throws ErrorFuturableTask.from()
Convert a Futurable to a FuturableTask:
typescript
const futurable = Futurable.fetch('/api/data');
const task = FuturableTask.from(futurable);Common Patterns
Resource Management
typescript
function managedResource() {
return new FuturableTask((resolve, reject, { onCancel }) => {
const resource = allocateResource();
// Register cleanup
onCancel(() => {
resource.cleanup();
});
resource.process()
.then(resolve)
.catch(reject);
});
}Multiple Async Operations
typescript
const task = new FuturableTask(async (resolve, reject, { signal }) => {
try {
const [users, posts] = await Promise.all([
fetch('/api/users', { signal }).then(r => r.json()),
fetch('/api/posts', { signal }).then(r => r.json())
]);
resolve({ users, posts });
} catch (error) {
reject(error);
}
});Conditional Execution
typescript
const task = new FuturableTask((resolve, reject, { signal }) => {
const interval = setInterval(() => {
if (signal.aborted) {
clearInterval(interval);
reject(new Error('Cancelled'));
return;
}
const condition = checkCondition();
if (condition) {
clearInterval(interval);
resolve('Condition met!');
}
}, 100);
});Progress Tracking
typescript
const task = new FuturableTask(async (resolve, reject, { signal }) => {
const steps = [step1, step2, step3, step4];
for (let i = 0; i < steps.length; i++) {
if (signal.aborted) {
reject(new Error('Cancelled'));
return;
}
updateProgress((i + 1) / steps.length * 100);
await steps[i]();
}
resolve('Complete');
});Type Parameters
T
The type of value the task will resolve to.
typescript
// Resolve with string
const stringTask = new FuturableTask<string>((resolve) => {
resolve('hello');
});
// Resolve with object
interface User {
id: number;
name: string;
}
const userTask = new FuturableTask<User>((resolve) => {
resolve({ id: 1, name: 'John' });
});
// Resolve with void
const voidTask = new FuturableTask<void>((resolve) => {
resolve();
});Comparison with Futurable Constructor
| Feature | FuturableTask | Futurable |
|---|---|---|
| Execution | Lazy (on .run()) | Eager (immediate) |
| Reusability | Multiple runs | Single use |
| Base | Independent class | Extends Promise |
| Use case | Composition & reuse | Promise replacement |
typescript
// Futurable: Executes immediately
const futurable = new Futurable((resolve) => {
console.log('Executing now!'); // Logs immediately
resolve(42);
});
// FuturableTask: Lazy execution
const task = new FuturableTask((resolve) => {
console.log('Executing now!'); // Nothing logged
resolve(42);
});
await task.run(); // Logs: "Executing now!"Notes
- The executor function is not called when the task is created
- Execution only happens when
.run()is called - Each call to
.run()creates a new independent execution - The
signalparameter in utils is always available - Multiple calls to
resolveorrejecthave no effect after the first call - The utils methods are bound to the task instance
See Also
- run() - Execute the task
- cancel() - Cancel the task
- onCancel() - Register cancellation callbacks
- FuturableTask.of() - Alternative constructor
- Introduction - Learn about FuturableTask
