Retrying an asynchronous operation is a pattern where a failed asynchronous operation is automatically executed again after certain time intervals. This is especially useful when working with network requests that may temporarily fail due to network issues, server problems, or overload.
Main approaches:
Implementing retry of asynchronous operations is an important technique for creating reliable web applications. It allows automatic recovery from temporary failures without user intervention.
When implementing retry, several important parameters need to be considered:
// Basic retry function
async function retryOperation(operation, maxRetries = 3) {
for (let i = 0; i <= maxRetries; i++) {
try {
return await operation();
} catch (error) {
if (i === maxRetries) throw error;
// Pause before next attempt
await delay(1000 * Math.pow(2, i));
}
}
}Same interval between all attempts:
function fixedDelayRetry(operation, retries, delayMs) {
// Retry with fixed delay
}Interval increases in geometric progression:
// Delays: 1s, 2s, 4s, 8s...
const delay = 1000 * Math.pow(2, attempt);Adding randomness to distribute load:
// Jitter reduces contention
const jitter = Math.random() * maxJitter;async function fetchWithRetry(url, options = {}) {
const { maxRetries = 3, retryDelay = 1000 } = options;
for (let i = 0; i <= maxRetries; i++) {
try {
const response = await fetch(url);
if (!response.ok) throw new Error('Request failed');
return response;
} catch (error) {
if (i === maxRetries) throw error;
await new Promise(resolve =>
setTimeout(resolve, retryDelay * Math.pow(2, i))
);
}
}
}function smartRetry(operation, config) {
const {
maxRetries = 3,
retryableErrors = ['NetworkError', 'TimeoutError']
} = config;
// Retry only for specific errors
}// ❌ Can lead to blocking
while (true) {
try {
await operation();
break;
} catch (error) {
// No attempt limit
}
}
// ✅ With attempt limit
for (let i = 0; i < maxRetries; i++) {
// Retry logic
}// ❌ Retry even fatal errors
if (error.status === 404) {
// Resource doesn't exist, retry is useless
}
// ✅ Retry only temporary errors
if (error.status >= 500 || error.status === 429) {
// Server errors and rate limiting
}Retry implementation works in all modern JavaScript environments, including browsers and Node.js.
Implementing retry of asynchronous operations is an important pattern for creating reliable web applications, helping to handle temporary network issues and server errors without user intervention.
What will be the result of executing this code and how to improve it?
async function unreliableOperation() {
if (Math.random() < 0.7) {
throw new Error('Network error');
}
return 'Success';
}
async function retry(func, times) {
try {
return await func();
} catch (error) {
if (times <= 0) throw error;
return retry(func, times - 1);
}
}
retry(unreliableOperation, 3);Answer: The result depends on the random factor, but in most cases there will be an “Network error”, as there is no delay between attempts.
Issues in the code:
Improved version:
async function improvedRetry(func, maxRetries = 3) {
for (let i = 0; i <= maxRetries; i++) {
try {
return await func();
} catch (error) {
// Retry only when maximum attempts reached
if (i === maxRetries) throw error;
// Exponential delay with jitter
const delay = 1000 * Math.pow(2, i);
const jitter = Math.random() * 500;
await new Promise(resolve =>
setTimeout(resolve, delay + jitter)
);
}
}
}Explanation: The improved version adds exponential delay and jitter, which prevents simultaneous retries from multiple clients and reduces server load. It also provides more predictable behavior and better error handling.
Want more articles to prepare for interviews? Subscribe to EasyAdvice, bookmark the site and improve yourself every day 💪