Skip to content
loading...

Javascript fetch, retry upon failure.

Jason Yu on March 27, 2018

This post is republished since the previous one was not showing up on my profile for some reason. So recently, I bumped into a situation where... [Read Full]
markdown guide
 

Thanks Jason. That's my version based on your example:

  const fetchWithRetry = (url) => {
    return new Promise((resolve, reject) => {
      let attempts = 1;
      const fetch_retry = (url, n) => {
        return fetch(url).then(resolve).catch(function (error) {
        if (n === 1) reject(error)
        else
        setTimeout(() => {
          attempts ++
          fetch_retry(url, n - 1);
        }, attempts * 3000)
      });
    }
      return fetch_retry(url, 5);
    });
  }

Then I can call:

fetchWithRetry(api/data/${guid}).then(requestProcess)

 

Hi, can I add the retries to the options?

fetch(url, {
retries: 3,
retryDelay: 1000
})
.then(function(response) {
return response.json();
})
.then(function(json) {
// do something with the result
console.log(json);
});

 

This is my version as a class.

It handle http response and has a delayed retry time.

export default class Comm {
    constructor() {
        this.endpoint = "/test-api";
    }

    async confirm(data) {

        const self = this;
        let attempts_left = 5;

        const fetch_options = {
            headers: {
                "Content-Type": "application/json",
                "Accept": "application/json"
            },
            method: "POST",
            body: JSON.stringify(data)
        };

        // FetchRetry function.
        const fetchRetry = async (url, options, attempt) => {
            try {
                const response = await fetch(url, options);

                if(!response.ok) {
                    throw new Error("Invalid response.");
                }
                return response;

            } catch (error) {
                if (attempt <= 1) {
                    throw error;
                }
                await self.sleep(2000);
                return fetchRetry(url, options, attempt - 1);
            }
        };

        return await fetchRetry(self.endpoint, fetch_options, attempts_left);
    }

    sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms))
    }
}
 

Perhaps add a check for a value smaller than 1 to avoid the infinite cycle:

try {
 ....
} catch (err) {
     if (retry === 1 || retry < 1) throw err;
          return await this.johnny(arg, retry - 1);
     }
}
 

Hello, I am a beginner of javascript . After watching your blog about promise ,especially this part-->
.....
.catch(function(error) {
fetch_retry(url, options, n - 1)
.then(resolve) // <--- simply resolve
.catch(reject); // <--- simply reject
})

I don't understand why resolve & reject can be included in then & catch functions directly... Is anything omitted?
Could you tell me why or where I can reference about this issue?
Sorry for my poor English.
I truely appreciate for your time.

 

Thanks for your comments! I am not sure if I understand your question correctly.

But it sounds like you are confused with the idea of "functions as first-class citizens", which is a fancy way of saying you can pass functions as a values around.

Are you familiar with setTimeout? Have a read about it here.

Consider

setTimeout(function() {
  print('hello')
}, 3000);

We are passing a function function () { print('hello'); } to setTimeout as the first argument. So if we call that function f, then we can equivilantly pass f to setTimeout.

const f = function () {
  print('hello');
}
setTimeout(f, 3000);

So in another words, my code:

.catch(function(error) {
  fetch_retry(url, options, n - 1)
    .then(resolve)
    .catch(reject);
})

Is basically equivalent to:

.catch(function(error) {
  fetch_retry(url, options, n - 1)
    .then(() => resolve())
    .catch(() => reject());
})

It is also important to note that the following is incorrect (or not the same):

.catch(function(error) {
  fetch_retry(url, options, n - 1)
    .then(resolve())
    .catch(reject());
})

Because Javascript will first evaluate resolve() and use the value it returns to pass on to then.

I hope I did help a little.

 
 

This is a very useful and perfectly written post. It not only provides an end result but also teaches you by showing the steps one would follow to write this function and improve it after some iterations, so you learn a way of thinking that can be applied to other functions you may want to write. Thank you for the post!

 

In the last line, do we really need to return await ...? i.e.

return await fetch_retry(url, options, n - 1);

?

Can we simply

return fetch_retry(url, options, n - 1);

?

 

You can omit the await. I like putting await because it reminds me that I am dealing with async functions and direct values instead of Promises. Although async/await are just playing with promises at the end of the day.

 

Sorry about the issue. We know all about what the problem was. Slighly less about what the solution is yet. We'll have it fixed soon, promise.

 

It's alright, copy and pasting isn't very hard. Only thing is that I lost my comments and likes. I have set my previous post to unpublished in case you guys fixed it and two articles show on my profile. haha

code of conduct - report abuse