Skip to main content

defer()

defer<T>(fn): Promise<T>

Defers execution of a function to the next tick of the event loop.

note

Uses setTimeout(0) to yield to the event loop.


Type Parametersโ€‹

T: Tโ€‹

The return type of the function.


Parametersโ€‹

fn: () => T | Promise<T>โ€‹

The function to defer.


Returns: Promise<T>โ€‹

Promise that resolves to the function result.


Throwsโ€‹

Rejects if the deferred function throws or rejects.


Sinceโ€‹

1.1.0


Also known asโ€‹

defer (Lodash, es-toolkit, Radashi) ยท โŒ (Remeda, Ramda, Effect, Modern Dash, Antfu)


Exampleโ€‹

await defer(() => updateDOM());

const result = await defer(async () => fetchData());

How it works?โ€‹

Defers function execution to the next tick of the event loop. Uses setTimeout(0) to yield control back to the browser/runtime before executing.

Practical Flowโ€‹


Use Casesโ€‹

Yield to the browser between heavy operations ๐Ÿ“Œโ€‹

Allow the browser to repaint and handle user input between CPU-intensive tasks. Essential for keeping UI responsive during long computations.

const processInChunks = async (items: Item[]) => {
const results: Result[] = [];

for (const chunk of chunks(items, 100)) {
// Process chunk
results.push(...chunk.map(heavyTransform));

// Yield to browser - allows repaint & input handling
await defer();
}

return results;
};

// UI stays responsive even with 10,000 items
await processInChunks(largeDataset);

Ensure state updates propagate before next operationโ€‹

Wait for React/Vue state updates to flush before reading DOM. Critical for accurate measurements after state changes.

const measureAfterUpdate = async () => {
setItems([...items, newItem]); // React state update

// Wait for React to flush and browser to repaint
await defer();

// Now DOM reflects the new state
const height = containerRef.current.scrollHeight;
containerRef.current.scrollTop = height;
};

Debounce rapid sequential calls naturallyโ€‹

Create a simple "next tick" debounce without timers. Useful for batching multiple synchronous updates.

let pendingUpdate: Promise<void> | null = null;

const batchedSave = async (data: Data) => {
latestData = data;

if (!pendingUpdate) {
pendingUpdate = defer(async () => {
await saveToServer(latestData);
pendingUpdate = null;
});
}

return pendingUpdate;
};

// Multiple rapid calls = single save with latest data
batchedSave({ a: 1 });
batchedSave({ a: 2 });
batchedSave({ a: 3 }); // Only this one is saved