Vishwasa Navada K
Vishwasa Navada K

Reputation: 642

Return value after all the promises are resolved

I am working on a nodejs code that fetches data from a site, parses it, finds particular data and fetches something else for the data that was previously fetched. But the final return statement is returning without the value fetched from the second API call.

I tried to implement async await, but I am not sure where do I have to put them exactly.

const getMainData = async val => {
  let result = [];

  //get xml data from the API
  const xmlData = await getSiteContent(`value`); //axios call

  parseString(xmlData, (err, json) => { //convert xml to json

    const { entry } = json.feed; // array of results.
    result = entry.map(report => {
      const secondInfo = getSomeMoreData(report.something); //axios call
      const data = {
        id: report.id,
        date: report.date,
        title: report.title
      };
      data.info = secondInfo;
      return data;
    });

  });


  return { result };
};

I was expecting the function to return the array result that has id, date, title and info. But I am getting info as null since it is going to another function that does one more API call.

Upvotes: 2

Views: 102

Answers (2)

mepley
mepley

Reputation: 539

Try wrapping parseString in a promise so you can await the result, then make the entry.map callback an async function so that you can use the await keyword to wait for the result of the axios fetch.

async function xml2json(xml) {
  return new Promise((resolve, reject) => {
    parseString(xml, function (err, json) {
      if (err)
        reject(err);
      else
        resolve(json);
    });
  });
}

const getMainData = async val => {
  //get xml data from the API
  const xmlData = await getSiteContent(`value`); //axios call

  const json = await xml2json(xmlData);
  const { entry } = json.feed; // array of results

  const result = await Promise.all(
    entry.map(async report => {
      const secondInfo = await getSomeMoreData(report.something); // axios call
      const data = {
        id: report.id,
        date: report.date,
        title: report.title,
      };
      data.info = secondInfo;
      return data;
    })
  )

  return { result };
}

Let me know if that works. If not, I can try to help you out further.

Upvotes: 1

PrivateOmega
PrivateOmega

Reputation: 2880

The problem with your code is you have mixed promises concept(async/await is a syntactic sugar - so same thing) along with callback concept.

And the return statement is outside callback() of parseString() and the callback would be executed maybe after returning results only because parseString() is an asynchronous function.

So in the following solution I have wrapped parseString() in a promise so that it can be awaited.

const parseStringPromisified = async xmlData => {
  return new Promise((resolve, reject) => {
    parseString(xmlData, (err, json) => {
      if (err) {
        reject(err);
      }
      resolve(json);
    });
  });
};

const getMainData = async val => {
  //get xml data from the API
  const xmlData = await getSiteContent(`value`); //axios call
  const json = await parseStringPromisified(xmlData);
  const { entry } = json.feed; // array of results.
  const result = entry.map(async report => {
    const secondInfo = await getSomeMoreData(report.something); //axios call
    return {
      id: report.id,
      date: report.date,
      title: report.title,
      info: secondInfo
    };
  });
  return Promises.all(result);
};

Upvotes: 1

Related Questions