TaskClass.prototype.finally(onFinally?: (() => void) | null): TaskClass<T, E>
Promise.prototype.finally, returning a Task so cleanup does not drop the chain into
plain-Promise land. Every spec behaviour is kept: onFinally takes no arguments, its return
value is discarded, a thenable it returns is awaited, and anything it throws replaces the
outcome.
Prefer try/finally to this. It exists so that calling it on a Task — which is a real
Promise, so anyone may — behaves sensibly, not because it is the better spelling. A plain
try/finally inside the recipe is better on every axis:
const acquire = async () => ({ read: async () => 'body', release: () => {} }); // preferred: lazy, retryable, and the cleanup runs once per attempt Task(async () => { const handle = await acquire(); try { return await handle.read(); } finally { handle.release(); } });
The reason is that this method must be EAGER — finally is overwhelmingly written
fire-and-forget (closeWithGrace(...).finally(() => process.exit(143))), and a lazy one
nobody awaited would never release. Being eager, it hands back a running Task, so
task.finally(cleanup).retry(3) leaves the first attempt's rejection unowned and reports an
unhandled rejection. retry first, finally last — or try/finally, which cannot be held
wrong this way.
let released = false; const value = await Task(() => 'body').finally(() => { released = true; // runs whichever way the Task settles }); value; // 'body' — the outcome passes through untouched released; // true