defer()
defer<
T>(fn):Promise<T>
Defers execution of a function to the next tick of the event loop.
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