retry
Retries a promise-returning function a specified number of times with exponential backoff. Attempts to execute the function, and if it fails, retries up to the specified number of times. Each retry waits longer than the previous one (exponential backoff). Useful for handling flaky network requests, rate-limited APIs, or temporary failures.
Installation
npx fragmen add promise/retrySource Code
/**
* Retries a promise-returning function a specified number of times with exponential backoff.
*
* Attempts to execute the function, and if it fails, retries up to the specified number of times.
* Each retry waits longer than the previous one (exponential backoff). Useful for handling
* flaky network requests, rate-limited APIs, or temporary failures.
*
* @param {() => Promise<T>} fn The async function to retry
* @param {object} options Configuration for retry behavior
* @param {number} options.retries Maximum number of retry attempts (default: 3)
* @param {number} options.delay Initial delay in milliseconds between retries (default: 1000)
* @param {number} options.backoff Multiplier for exponential backoff (default: 2)
* @returns {Promise<T>} A promise that resolves with the function's result or rejects after all retries fail
*
* @example
* ```typescript
* // Retry a fetch request
* const fetchData = () => fetch('https://api.example.com/data');
* const result = await retry(fetchData, { retries: 3 });
*
* // Custom retry configuration
* const unstableOperation = async () => {
* const response = await fetch('/api/unstable');
* if (!response.ok) throw new Error('Failed');
* return response.json();
* };
*
* const data = await retry(unstableOperation, {
* retries: 5,
* delay: 500,
* backoff: 2
* });
* // Retries: 500ms, 1000ms, 2000ms, 4000ms, 8000ms
*
* // With single retry
* const quickRetry = await retry(fetchData, { retries: 1, delay: 100 });
* ```
*/
export async function retry<T>(
fn: () => Promise<T>,
options: {
retries?: number;
delay?: number;
backoff?: number;
} = {}
): Promise<T> {
const { retries = 3, delay: initialDelay = 1000, backoff = 2 } = options;
// Validate inputs
if (typeof fn !== 'function') {
throw new TypeError('fn must be a function');
}
if (retries < 0 || !Number.isInteger(retries)) {
throw new RangeError('retries must be a non-negative integer');
}
if (initialDelay < 0) {
throw new RangeError('delay must be non-negative');
}
if (backoff <= 0) {
throw new RangeError('backoff must be positive');
}
let lastError: unknown;
let currentDelay = initialDelay;
for (let attempt = 0; attempt <= retries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
// If this was the last attempt, throw the error
if (attempt === retries) {
throw error;
}
// Wait before next retry with exponential backoff
await new Promise(resolve => setTimeout(resolve, currentDelay));
currentDelay *= backoff;
}
}
// This should never be reached, but TypeScript needs it
throw lastError;
}
Examples
// Retry a fetch request
const fetchData = () => fetch('https://api.example.com/data');
const result = await retry(fetchData, { retries: 3 });
// Custom retry configuration
const unstableOperation = async () => {
const response = await fetch('/api/unstable');
if (!response.ok) throw new Error('Failed');
return response.json();
};
const data = await retry(unstableOperation, {
retries: 5,
delay: 500,
backoff: 2
});
// Retries: 500ms, 1000ms, 2000ms, 4000ms, 8000ms
// With single retry
const quickRetry = await retry(fetchData, { retries: 1, delay: 100 });
Related Utilities
all-settled-typed
promiseType-safe Promise.allSettled with separated results
delay
promiseReturns a promise that resolves after a given number of milliseconds. Creates an artificial delay using Promise and setTimeout. Useful for implementing timeouts, rate limiting, animation delays, or simulating async operations in testing.
timeout
promiseWraps a promise with a timeout, rejecting if it doesn't resolve within the specified time. Creates a race between the provided promise and a timeout. If the promise doesn't resolve or reject before the timeout, it will be rejected with a timeout error. Useful for preventing indefinite hangs, enforcing SLAs, or handling slow operations gracefully.
Quick Actions
Parameters
fn() => Promise<T>The async function to retry
optionsobjectConfiguration for retry behavior
Returns
Promise<T>A promise that resolves with the function's result or rejects after all retries fail