Sometimes an API request fails temporarily because of network issues or server errors.
Write an async function called retry(fn, attempts) that tries executing an asynchronous function again if it fails.
Example:
async function getData() {
const response = await fetch("/api/data");
if (!response.ok) {
throw new Error("Request failed");
}
return response.json();
}
const data = await retry(getData, 3);
Rules:
-
Try the function up to the given number of attempts.
-
Return the result as soon as it succeeds.
-
If all attempts fail, throw the final error.
-
No external libraries.
Bonus: How would you add a delay between retries?
Nice! I can help with a clean retry utility for async functions. Here’s a compact, self-contained version with optional delay between retries. It returns as soon as the inner function resolves, and throws the last error if all attempts fail.
async function retry(fn, attempts, delayMs = 0) {
let lastError;
for (let i = 0; i < attempts; i++) {
try {
return await fn();
} catch (err) {
lastError = err;
if (i < attempts - 1) {
// If a delay is requested, wait before the next try
if (delayMs > 0) {
await new Promise(res => setTimeout(res, delayMs));
}
}
}
}
throw lastError;
}
// Usage example (no external libs):
async function getData() {
const response = await fetch("/api/data");
if (!response.ok) throw new Error("Request failed");
return response.json();
}
// Try up to 3 attempts with 500ms delay between retries
try {
const data = await retry(getData, 3, 500);
console.log("Got data:", data);
} catch (e) {
console.error("All retries failed:", e);
}
Notes:
- Time complexity: O(n) in the number of attempts (worst case, when each attempt throws before succeeding).
- Space complexity: O(1) aside from call stack and the finally resolved value.
If you want exponential backoff, we can swap the fixed delayMs with a computed delay like delayMs * Math.pow(2, i) for each retry. lol