4
\$\begingroup\$

I'm trying to call a promise recursively. If I get a responseData with a key error I want to call the promise again and again until I don't get it.

  _getUser (url) {
    console.log('fetching url', url)
    return fetch(`$(url)/api`, {
      method: 'POST',
      headers: {},
      body: '{"key" : "body"}'
    })
    .then((response) => response.json())
    .then((responseData) => {
      console.log('Getting responseData', responseData)
      if (responseData[0].error) {
        alert(responseData[0].error.description)
        return _getUser(url)
      } else alert('User Created')
    })
    .catch((error) => {
      console.log(error)
    })
  }

Is this the best way to call a promise recursively to do what I want?

\$\endgroup\$
3
  • \$\begingroup\$ It won't work at all unless you return _getUser(url);. \$\endgroup\$
    – torazaburo
    Commented Sep 1, 2016 at 9:18
  • 1
    \$\begingroup\$ Yep sorry I forgot that. Anything else? \$\endgroup\$
    – LuisPinto
    Commented Sep 1, 2016 at 9:21
  • \$\begingroup\$ You're never checking response's status code and stuff, so if there's an actual error that doesn't return JSON there won't be a retry. And the caller of your function cannot even distinguish the two cases, since you're catching all errors an return undefined just as in the success case. The general approach at recursion is fine however. \$\endgroup\$
    – Bergi
    Commented Sep 1, 2016 at 9:31

2 Answers 2

2
\$\begingroup\$

Two things you can improve:

Retry in all error cases by doing the recursive call in the catch function. And limit the number of retries

_getUser (url, triesRemaining) {
    console.log('fetching url', url)
    return fetch(`$(url)/api`, {
      method: 'POST',
      headers: {},
      body: '{"key" : "body"}'
    })
    .then((response) => response.json())
    .then((responseData) => {
      console.log('Getting responseData', responseData)
      if (responseData[0].error) {
        alert(responseData[0].error.description)
        throw new Error();
      } else alert('User Created')
    })
    .catch((error) => {
      console.log(error)
      if(triesRemaining>0) {
        return _getUser(url,triesRemaining-1)
      } else {
        throw new Error('Could not create user. Max amount of tries reached');
      }
    })
  }
\$\endgroup\$
1
\$\begingroup\$

In addition to Pieter's suggestions, you could generalize this pattern into a withRetries function:

withRetries (n, body) {
  // Attempts to execute body.
  // If an exception is thrown, body will be retried up to n times.
  // If the nth time fails, the exception is propagated.
  return body()
  .catch((error) => {
    console.log(error)
    if (n > 0) {
      return withRetries(n - 1, body)
    } else {
      throw new Error('Maximum number of retries exceeded');
    }
  })
}

Now we can write _getUser as:

_getUser (url) {
  console.log('fetching url', url)
  return withRetries(MAX_RETRIES, function() {
    return fetch(`$(url)/api`, {
      method: 'POST',
      headers: {},
      body: '{"key" : "body"}'
    })
    .then((response) => response.json())
    .then((responseData) => {
      console.log('Getting responseData', responseData)
      if (responseData[0].error) {
        alert(responseData[0].error.description)
        throw new Error(); // Fail and retry
      } else alert('User Created')
    })
  })
}

You could further factor out the JSON parsing / error handling code into its own function as well.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.