https://bigfrontend.dev/problem/retry-promise-on-rejection
For a web application, fetching API data is a common task.
But the API calls might fail because of Network problems. Usually we could show a screen for Network Error and ask users to retry.
One approach to handle this is auto retry when network error occurs.
You are asked to create a fetchWithAutoRetry(fetcher, count)
, which automatically fetch again when error happens, until the maximum count is met.
For the problem here, there is no need to detect network error, you can just retry on all promise rejections.
Write a function that retries fetch upon failure up to N times. The function takes two inputs, a callback function that fetches API data and returns a promise, and an integer representing maximum retry count.
Fetching data is always asynchronous, so the function needs to return a promise. Within the promise, we can use a try...catch
block to implement the auto retry. Call the fetcher
function in the try
block and then resolve
the result. If an error is thrown in the try
block, the statement in the catch
block will be executed. So in the catch
block, we can try to fetch the data again if the maximum count is not reached. We can use the variable maximumRetryCount
to keep track of how many tries we have left. Every time we retry, we decrease the maximumRetryCount
by 1. If maximumRetryCount
is equal to 0, the returned promise gets rejected with the thrown error as its value.
/**
* @param {() => Promise<any>} fetcher
* @param {number} maximumRetryCount
* @return {Promise<any>}
*/
function fetchWithAutoRetry(fetcher, maximumRetryCount) {
return new Promise((resolve, reject) => {
const retry = async (retriesLeft) => {
try {
const data = await fetcher();
resolve(data);
} catch (err) {
if (retriesLeft === 0) {
reject(err);
return;
}
retry(retriesLeft - 1);
}
};
retry(maximumRetryCount);
});
}
const fetcher = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((response) => response.json())
.then((data) => resolve(data))
.catch((err) => reject(err));
}, 1000);
});
};
console.log("Start");
fetchWithAutoRetry(fetcher, 5)
.then((data) => console.log(data))
.catch((err) => console.log(err));
console.log("End");