使用Promise.all进行多个API调用并调度操作

时间:2019-08-19 07:26:30

标签: javascript reactjs asynchronous redux es6-promise

我想调用多个API并将每个响应数据存储在一个对象中,然后我希望分派此响应对象,但是我不确定。

下面是我尝试的代码。我可以知道我在哪里做错了吗?

/* COMPONENT.JSX */
componentDidMount() {
  callApis(this.props.products, this.props.profileId);
}

/* API.JS */
const getContactDetails = (http, profileId) => 
 (http.get(`https://www.fakeurl.com/${profileId}/contact`));

const getProductDetails = (http, profileId) => 
  (http.get(`https://www.fakeurl.com/${profileId}/product`));

const callApis = (products, profileId) => (dispatch) => {

  const payload = new Map();

  products.forEach((product) => {

  const apis = [getContactDetails, getProductDetails];

  apis.map(api => api(http, profileId));

  Promise.all(apis)
      .then((response) => {
          const apiData = {
              contactData: getParsedContactData(response[0]),
              productData: getParsedProductData(response[1])
          };
          if (payload.get(product.token)) {
              payload.get(companion.token).push(apiData);
          } else {
              payload.set(product.token, [apiData]);
          }
      })
      .catch(err => {
          throw ('An error occurred ', err);
      });
   });
   dispatch({ type: FETCH_API_DATA, payload: payload });
}

我希望在所有API都解决之后,将调用分派,进行解析,然后映射到有效负载对象中,然后应该分派。

2 个答案:

答案 0 :(得分:0)

Array.map返回一个新的数组,您将其丢弃

您正在运行任何异步代码之前调用调度

需要一些小的更改

/* API.JS */
const getContactDetails = (http, profileId) => http.get(`https://www.fakeurl.com/${profileId}/contact`);

const getProductDetails = (http, profileId) => http.get(`https://www.fakeurl.com/${profileId}/product`);

const callApis = (products, profileId) => (dispatch) => {
    const payload = new Map();
    // *** 1
    const outerPromises = products.map((product) => {

        const apis = [getContactDetails, getProductDetails];
        // *** 2
        const promises = apis.map(api => api(http, profileId));

        // *** 3
        return Promise.all(promises)
        .then((response) => {
            const apiData = {
                contactData: getParsedContactData(response[0]),
                productData: getParsedProductData(response[1])
            };
            if (payload.get(product.token)) {
                payload.get(companion.token).push(apiData);
            } else {
                payload.set(product.token, [apiData]);
            }
        })
        .catch(err => {
            throw ('An error occurred ', err);
        });
    }));
    // *** 4
    Promise.all(outerPromises)
    .then(() => dispatch({
            type: FETCH_API_DATA,
            payload: payload
        })
    )
    .catch(err => console.log(err));
}
  1. 使用products.map代替liproc.forEach
  2. 在apis.map中捕获要在Promise.all中使用的承诺
  3. return Promise.all,因此可以等待外部承诺
  4. Promise.all来自外部,等待一切完成。

答案 1 :(得分:-2)

const callApis = (products, profileId) => async (dispatch) => { // use async function
  const payload = new Map();
  for (const product of products) {
    const apis = [getContactDetails, getProductDetails];

    apis.map(api => api(http, profileId));

    await Promise.all(apis)  // await all promise done
      .then((response) => {
        const apiData = {
          contactData: getParsedContactData(response[0]),
          productData: getParsedProductData(response[1])
        };
        if (payload.get(product.token)) {
          payload.get(companion.token).push(apiData);
        } else {
          payload.set(product.token, [apiData]);
        }
      })
      .catch(err => {
        throw ('An error occurred ', err);
      });
  }
  dispatch({ type: FETCH_API_DATA, payload: payload }); // dispatch will be executed when all promise done
}