Skip to content Skip to sidebar Skip to footer

Javascript Promise Inside Async/await Function Resolve Final Array Of Responses

I'm quite a newbie in JavaScript and in Promises. I'm trying to build an array of objects that I get from an API. To do so, I've build two functions in a file MyFile.js. The first

Solution 1:

This is a bit untested

const api_url = 'https://some_url.com/api/data';

get_data(api_url).then((results) => {
  console.log(results);
}).catch((error) => {
   // console.error(error);
});

functionget_items (url) {
  const options = {
    baseURL: url,
    method: 'get'
  };

  returnaxios(options).then((response) => response.data);
}

asyncfunctionget_data(next_url) {
  const output = [];

  while (next_url) {
    const { results, next } = awaitget_items(next_url);
    output.push(...results);
    next_url = next;
  }

  return output;
}

Basically it makes things a bit neater. I suggest to look at more examples with Promises and the advantage and when to ease await/async. One thing to keep in mind, if you return a Promise, it will follow the entire then chain, and it will always return a Promise with a value of the last then.. if that makes sense :)

Solution 2:

There are a few problems. One is that you never resolve the initial Promise unless the else block is entered. Another is that you should return the recursive get_data call every time, so that it can be properly chained with the initial Promise. You may also consider avoiding the explicit promise construction antipattern - get_items already returns a Promise, so there's no need to construct another one (same for the inside of get_items, axios calls return Promises too).

You might consider a plain while loop, reassigning the next_url string until it's falsey:

functionget_items (baseURL) {
  const options = {
    baseURL: url,
    method: 'get'
  }
  // return the axios call, handle errors in the consumer instead:returnaxios(options)
    .then(res => res.data)
}

asyncfunctionget_data() {
  const output = []
  let next_url = 'https://some_url.com/api/data'try {
    while (next_url) {
      const response = awaitget_items(next_url);
      output.push(...response.results)
      next_url = response.next;
    }
  } catch (e) {
    // handle errors *here*, perhapsconsole.log(e)
  }
  return output;
}

Note that .catch will result in a Promise being converted from a rejectedPromise to a resolved one - you don't want to .catch everywhere, because that will make it difficult for the caller to detect errors.

Solution 3:

Another way of doing it is to not use async at all and just recursively return a promise:

constgetItems = (url) =>
  axios({
    baseURL: url,
    method: 'get',
  }).then((response) => response.data);

constgetData = (initialUrl) => {
  constrecur = (result, nextUrl) =>
    !nextUrl
      ? Promise.resolve(result)
      : getItems(nextUrl).then((data) =>recur(result.concat([data.results]), data.next),
        );
  returnrecur([],initialUrl)
    .catch(e=>Promise.reject(e.stack));//reject with error stack
};

As CertainPerformance noted; you don't need to catch at every level, if you want getData to reject with error.stack you only need to catch it once.

However; if you had 100 next urls and 99 of them were fine but only the last one failed would you like to reject in a way that keeps the results so far so you can try again?

If you do then the code could look something like this:

constgetData = (initialUrl) => {
  constrecur = (result, nextUrl) =>
    !nextUrl
      ? Promise.resolve(result)
      : getItems(nextUrl)
        .catch(e=>Promise.reject([e,result]))//reject with error and result so far
        .then((data) =>recur(result.concat([data.results]), data.next),
        );
  returnrecur([],initialUrl);//do not catch here, just let it reject with error and result
};

Post a Comment for "Javascript Promise Inside Async/await Function Resolve Final Array Of Responses"