Search code examples
javascriptpollingaxios

Looping API calls with Axios and Promises


I'm using Axios to make API calls, and for one call I'd like to continue polling the API until I get a response.

However, when I call this function something resolves the promise earlier than expected.

I call the function here:

componentDidMount() {
  api.getUser(this.props.user.id)
  .then((response) => {
    console.log(response);
    this.handleSuccess(response.content);
  })
  .catch((error) => {
    this.handleError(error);
  });
}

And the console.log on line 4 shows undefined. The function does continue polling and stops when it receives valid data.

The function itself:

getUser(id, retries = 0) {
  return axios(getRequestConfig)
  .then((res) => {
    if (res.data && res.data.content.status === 200) {
      return Promise.resolve(res.data); // success!
    } else if (retries >= 15) {
      return Promise.reject(res); // failure
    } else {
      // try again after delay
      delay(1000)
      .then(() => {
        return this.getUser(id, retries + 1);
      })
    }
  })
  .catch(err => err);
}

Solution

  • I'd outsorce the polling logic into a seperate function:

    //expects fn() to throw if it failed
    //if it runs out of retries, poll() will resolve to an rejected promise, containing the latest error
    function poll(fn, retries = Infinity, timeoutBetweenAttempts = 1000){
        return Promise.resolve()
            .then( fn )
            .catch(function retry(err){
                if(retries-- > 0)
                    return delay( timeoutBetweenAttempts )
                        .then( fn )
                        .catch( retry );
                throw err;
            });
    }
    
    
    
    getUser(id) {
        function validate(res){
            if(!res.data || res.data.content.status !== 200) 
                throw res; 
        }
        return poll(() => axios(getRequestConfig).then(validate), 15, 1000);
    }