16

I'm using browser's native fetch API for network requests. Also I am using the whatwg-fetch polyfill for unsupported browsers.

However I need to retry in case the request fails. Now there is this npm package whatwg-fetch-retry I found, but they haven't explained how to use it in their docs. Can somebody help me with this or suggest me an alternative?

vsync
  • 103,437
  • 51
  • 275
  • 359
dsaket
  • 1,707
  • 2
  • 18
  • 30
  • Does this answer your question? [How to try JS fetch() method in a loop](https://stackoverflow.com/questions/60289882/how-to-try-js-fetch-method-in-a-loop) – ggorlen Jan 31 '21 at 19:29

3 Answers3

20

From the fetch docs :

fetch('/users')
    .then(checkStatus)
    .then(parseJSON)
    .then(function(data) {
          console.log('succeeded', data)
    }).catch(function(error) {
          console.log('request failed', error)
    })

See that catch? Will trigger when fetch fails, you can fetch again there. Have a look at the Promise API.

Implementation example:

function wait(delay){
    return new Promise((resolve) => setTimeout(resolve, delay));
}

function fetchRetry(url, delay, tries, fetchOptions = {}) {
    function onError(err){
        triesLeft = tries - 1;
        if(!triesLeft){
            throw err;
        }
        return wait(delay).then(() => fetchRetry(url, delay, triesLeft, fetchOptions));
    }
    return fetch(url,fetchOptions).catch(onError);
}

Edit 1: as suggested by golopot, p-retry is a nice option.

Edit 2: simplified example code.

Isidrok
  • 1,785
  • 8
  • 15
  • This is exactly what I'm currently doing. But I'm looking for something like an additional optional { retry: 3, //max number of retries retryTimeout: 3000 //timeout between successive requests } – dsaket Sep 12 '17 at 13:18
  • I just updated the example with what I think should be a working version, you may need some tweak tough. Tell me if u want some comments in the code to make it clearer. – Isidrok Sep 12 '17 at 19:10
  • This is [needlessly complex](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it) – Benjamin Gruenbaum May 14 '20 at 10:35
  • Thansk for pointing that out @BenjaminGruenbaum the code was pretty messy – Isidrok Jun 14 '20 at 21:27
8

I recommend using some library for promise retry, for example p-retry.

Example:

const pRetry = require('p-retry')
const fetch = require('node-fetch')

async function fetchPage () {
  const response = await fetch('https://stackoverflow.com')

  // Abort retrying if the resource doesn't exist
  if (response.status === 404) {
    throw new pRetry.AbortError(response.statusText)
  }

  return response.blob()
}

;(async () => {
  console.log(await pRetry(fetchPage, {retries: 5}))
})()
golopot
  • 8,948
  • 5
  • 32
  • 44
2

I don't like recursion unless is really necessary. And managing an exploding number of dependencies is also an issue. Here is another alternative in typescript. Which is easy to translate to javascript.

interface retryPromiseOptions<T>  {
    retryIf?:(response:T) => boolean, 
    retries?:number
}

function retryPromise<T>(promise:() => Promise<T>, options:retryPromiseOptions<T>) {
    const { retryIf = (_:T) => false, retries = 1} = options
    let _promise = promise();

    for (var i = 0; i < retries; i++)
        _promise = _promise.then((value) => retryIf(value) ? promise() : Promise.reject(value));
    
    return _promise;
}

And use it this way...

retryPromise(fetch(url),{
    retryIf: (response:Response) => true, // you could check before trying again
    retries: 5
}).then( ... my favorite things ... )

I wrote this for the fetch API on the browser. Which does not issue a reject on a 500. And did I did not implement a wait. But, more importantly, the code shows how to use composition with promises to avoid recursion.

Arturo Hernandez
  • 2,459
  • 2
  • 26
  • 34
  • For you its easy to translate to javascript, however for me everything you've written there looks exactly like javascript. Could you translate this to js for me and others like me? – problemlow Apr 29 '22 at 06:07