简体   繁体   中英

Building an object with multiple async/await calls

I'm using an api that has data on two endpoints:

  • /news gets me the list of articles which includes a small amount of properties
  • /news/{id}/metadata gets all of the properties of an article

I actually need to get all of the properties and I'm planning to build a master object to drive my UI.

Current functions:

  • getNews: an async/await function that successfully gets article list from /news
  • getMetaPerArticle: another async/await function that takes an ID and call /news/{id}/metadata

Behaviour:

  • I run the getNews async functions and wait for the response
  • when the response comes through I map over the response array and run the getMetadata function on each of the items in the array
  • once getMetadata is complete, result is stored to a constant, and assigned to the element.metadata

Problem : - both my functions resolve, but my final object contains Promise.resolve objects. The objects have the correct values.

Code

const getNews = async options => {
    try {
      const { data } = await axios(options);
      const parsedEnDataWithMeta = parsedEnData.map(article => {
        const mergedArticleWithMeta = {
          ...article,
          ...getMetaPerArticle(article.id)
        };
        return mergedArticleWithMeta;
      });
    } catch (getNewsError) {
      dispatch(receiveNewsError(getNewsError));
    }
  };



const getMetaPerArticle = async articleID => {
    const axiosOptions = {
      method: "GET",
      url: `url`,
    };
    try {
      const response = await axios(axiosOptions);
      return response.data;
    } catch (err) {
      console.error(err);
      dispatch(receiveNewsError(err));
    }
  };

Output

(6) [{…}, {…}, {…}, {…}, {…}, {…}]
0: {
    abstract: "",
    ...
    metadata: Promise {<resolved>: {...}}
}

getMetaPerArticle returns a promise, so you'll need to wait for those promises to resolve before you try to map to parsedEnDataWithMeta. Something like this:

const getNews = async options => {
  try {
    const { data } = await axios(options);
    const metadataPromises = data.map(article => getMetaPerArticle(article.id));
    const metadata = await Promise.all(metadataPromises);
    const parsedEnDataWithMeta = data.map((article, i) => ({
      ...article,
      ...metadata[i]
    });
  } catch (getNewsError) {
    dispatch(receiveNewsError(getNewsError));
  }
};

Your Problem is that getMetaPerArticle returns a Promise so you need to add an await in fornt of it, and mark the arrow function as async .

const parsedEnDataWithMeta = parsedEnData.map(async article => {
  const mergedArticleWithMeta = {
    ...article,
    ...await getMetaPerArticle(article.id)
  };
  return mergedArticleWithMeta;
});

After that parsedEnDataWithMeta will hold a list of Promises, so you would need to wait untill all of them are resolved using Promise.all :

const parsedEnDataWithMeta = await Promise.all(parsedEnData.map(async article => {
  const mergedArticleWithMeta = {
    ...article,
    ...await getMetaPerArticle(article.id)
  };
  return mergedArticleWithMeta;
}));

If you need to use that more often then you could define you a map function that will handle promises:

function promiseMap( array, callback ) {
  return Promise.all(array.map(callback))
}


const parsedEnDataWithMeta = await promiseMap(parsedEnData, async article => {
  const mergedArticleWithMeta = {
    ...article,
    ...await getMetaPerArticle(article.id)
  };
  return mergedArticleWithMeta;
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM