Skip to content

Instantly share code, notes, and snippets.

@PetukhovArt
Created December 30, 2024 16:23
Show Gist options
  • Save PetukhovArt/7857c198ad677e6eebfb9fd472213b28 to your computer and use it in GitHub Desktop.
Save PetukhovArt/7857c198ad677e6eebfb9fd472213b28 to your computer and use it in GitHub Desktop.
// условия :
// если исчерпали попытки, то throw последнюю ошибку
// retryCount - количество попыток ретрая при не успехе
// timeoutMs - таймаут, если не успевает разрешиться промис, то абортим запрос
// 1 решение через рекурсию
// Если количество попыток (retryCount) будет очень большим,
// это может привести к переполнению стека вызовов, лучше использовать цикл
function retryFetch1(url, { retryCount, timeoutMs }) {
return new Promise((resolve, reject) => {
let lastError = null;
let timeoutId = null;
const controller = new AbortController();
const setTimer = () => {
timeoutId = setTimeout(() => {
controller.abort();
}, timeoutMs);
};
setTimer();
const tryFetch = (retries) => {
return fetch(url, { signal: controller.signal })
.then((res) => {
clearTimeout(timeoutId);
console.log("resolve, response: ", res);
if (res.ok) {
// resolve promise
resolve(res.json());
} else {
// to catch
throw new Error("unknown error");
}
})
.catch((err) => {
console.log("catch, retries: ", retries);
clearTimeout(timeoutId);
if (retries === 0) {
// reject promise
reject(lastError ?? "unknown error");
} else {
lastError = err;
setTimer();
// retry
tryFetch(retries - 1);
}
});
};
tryFetch(retryCount - 1);
});
}
// через while
function retryFetch2(url, { retryCount, timeoutMs }) {
let attempts = 0;
let lastError = null;
return new Promise(async (resolve, reject) => {
const controller = new AbortController();
let timeoutId = null;
const setAbortTimer = () => {
timeoutId = setTimeout(() => {
controller.abort("timeout abort");
}, timeoutMs);
};
setAbortTimer();
while (attempts !== retryCount) {
if (attempts !== 0) {
setAbortTimer();
}
attempts++;
try {
console.log("fetch attempt", attempts);
const res = await fetch(url, { signal: controller.signal });
clearTimeout(timeoutId);
if (res.ok) {
resolve(res.json());
}
} catch (e) {
clearTimeout(timeoutId);
lastError = e;
if (attempts === retryCount) {
reject(lastError);
}
}
}
});
}
console.log(
retryFetch2("https://api.restful-api.", {
retryCount: 3,
timeoutMs: 3000,
})
.then((res) => {
console.log(res);
})
.catch((err) => console.log(err)),
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment