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';
// or, from the all-in-one package (same code, one install):
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'

Callback registered via the defer function. Receives the error if the main work threw.

type DeferCallback = (error?: unknown) => void | Promise<void>

View source on GitHub