Как повторить неудачную операцию
Короткий ответ
Вызывайте функцию в цикле. Если она выполнилась — верните результат, если нет — попробуйте снова, а после последней попытки передайте ошибку дальше:
async function retry(task, attempts = 3) {
for (let i = 1; i <= attempts; i++) {
try {
return await task();
} catch (error) {
console.log(`attempt ${i} failed: ${error.message}`);
if (i === attempts) throw error;
}
}
}
let calls = 0;
const unstable = async () => {
calls++;
if (calls < 3) throw new Error('server busy');
return 'data';
};
console.log(await retry(unstable));Результат:
attempt 1 failed: server busy
attempt 2 failed: server busy
dataРастущая пауза
Не повторяйте сразу: после каждой неудачи ждите дольше. Это называется экспоненциальной задержкой, она даёт серверу время прийти в себя:
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function retry(task, attempts = 4, delay = 100) {
for (let i = 0; i < attempts; i++) {
try {
return await task();
} catch (error) {
if (i === attempts - 1) throw error;
const wait = delay * 2 ** i;
console.log(`waiting ${wait} ms`);
await sleep(wait);
}
}
}
let calls = 0;
const result = await retry(async () => {
if (++calls < 4) throw new Error('timeout');
return 'ok';
});
console.log(result);Результат:
waiting 100 ms
waiting 200 ms
waiting 400 ms
okС fetch
Повторяйте только временные сбои: ошибки сети и статусы от 500. Ошибка 404 после паузы не исчезнет:
const response = await retry(async () => {
const res = await fetch('/api/orders');
if (res.status >= 500) throw new Error(`Server error ${res.status}`);
return res;
});Частая ошибка
Без await в return await task() ошибка промиса не перехватывается внутри try, и повтора не происходит:
async function retryBroken(task) {
for (let i = 1; i <= 3; i++) {
try {
return task();
} catch {
console.log('retrying');
}
}
}
try {
await retryBroken(async () => {
throw new Error('failed');
});
} catch (error) {
console.log('no retries:', error.message);
}Результат:
no retries: failedФункции из этого ответа
- Promise — Обещание результата, который будет готов позже: успех или ошибка.
- async function — Функция, которая всегда возвращает промис и внутри которой можно использовать await.
- try...catch — Перехватывает ошибки, чтобы программа не остановилась.