Skip to content

defer

Runs an async function and guarantees that all deferred callbacks are executed afterwards, in LIFO order (last registered = first executed), regardless of whether the main work succeeds or throws.

Inspired by Radashi’s defer. Useful for resource cleanup, temporary file removal, or any “undo” logic that must run even on failure.

Available since v2.0.0

import { defer } from '@helpers4/promise';
defer<T>(fn: function): Promise<T>
ParameterTypeDescription
fnfunctionAn async function that receives a defer registration function.

Promise<T> — The resolved value of fn.

Registered callbacks execute after the main function, even on success.

const result = await defer(async (d) => {
  d(() => console.log('cleanup'));
  return 42;
});
// logs: 'cleanup' — result is 42

Multiple callbacks are called in reverse registration order.

await defer(async (d) => {
  d(() => console.log('step 1'));
  d(() => console.log('step 2'));
  d(() => console.log('step 3'));
});
// logs: 'step 3', 'step 2', 'step 1'

Callbacks still execute when the main function throws; the error is re-thrown after.

const releaseLock = () => console.log('lock released');
await defer(async (d) => {
  d(releaseLock);
  throw new Error('something failed');
}).catch(() => {});
// logs: 'lock released'

View source on GitHub