1

I have the following JS function:

func() {
  return fetch({
    ...
  }).then({
    ...
  })catch({
    ...
  })
}

In it I return a promise returned by fetch(). In the event that it fails (ie calls catch() block) I want to repeat the whole thing. Something like having the whole thing in a while (true) loop, but I can't figure out how to do this with promises.

Any suggestions?

VLAZ
  • 26,331
  • 9
  • 49
  • 67
gkeenley
  • 6,088
  • 8
  • 54
  • 129
  • Does this answer your question? [fetch retry request (on failure)](https://stackoverflow.com/questions/46175660/fetch-retry-request-on-failure) – ggorlen Feb 18 '20 at 22:07

2 Answers2

1

you should have a close look to promises and async await.

async function fetchUntilSucceeded() {
  let success = false;
  while(!success) {
    try {
      let result = await fetch(...);
      success = true;
      //do your stuff with your result here
    } catch {
      //do your catch stuff here
    }
  }
}

If you just need the results:

async function fetchUntilSucceeded() {
  while(true) {
    try {
      return await fetch(...);
    } 
  }
}

But be careful with such code as it might never resolve! also it can send a lot of requests without any waittime in between.

Michriko
  • 337
  • 1
  • 11
0

You can simply write a loop and count down the attempts until one succeeds or you run out. async/await makes this easy. See below for a minimal, complete example.

Note that the fetch API uses the response.ok flag to ensure that the response status falls in the 200 range. Wrapping with a try/catch is only sufficient to cover connection failures. If the response indicates a bad request, a retry is likely inappropriate. This code resolves the promise in such cases but you could consider !response.ok as an error and retry if you wish.

const fetchWithRetry = async (url, opts, tries=2) => {
  const errs = [];
  
  for (let i = 0; i < tries; i++) {
    // log for illustration
    console.log(`trying GET '${url}' [${i + 1} of ${tries}]`);
    
    try {
      return await fetch(url, opts);
    }
    catch (err) {
      errs.push(err);
    }
  }
  
  throw errs;
};

fetchWithRetry("https://httpstat.us/400")
  .then(response => console.log("response is OK? " + response.ok))
  .catch(err => console.error(err));

fetchWithRetry("foo")
  .catch(err => console.error(err.map(e => e.toString())));

fetchWithRetry("https://httpstat.us/200")
  .then(response => response.text())
  .then(data => console.log(data))
  .catch(err => console.error(err));

Pass the tries parameter as -1 if you want an infinite number of retries (but this doesn't seem like the common case to me).

ggorlen
  • 44,755
  • 7
  • 76
  • 106