【问题标题】:Is it possible to use axios.all with a then() for each promise?是否可以将 axios.all 与 then() 一起用于每个承诺?
【发布时间】:2017-09-25 15:34:54
【问题描述】:

我有一个触发事件以获取数据的 React 组件。这会导致动态数量的存储过程调用来获取数据,并且每次调用的数据都存储在完全不同的位置。然后,一旦收到所有数据并可用,我就需要重新渲染。我在 axios 中使用 Promise。

由于 axios 调用的次数是动态的,我正在构建一个数组并将其插入到axios.all 中,如下所示:

let promises = [];

for (let i = 0; i < requests.length; i++) {
    promises.push(axios.get(request[i].url, { params: {...} }));
}

axios.all(promises).then(/* use the data */);

问题是每个 axios 请求返回的数据被添加到一个完全不同的位置的对象中。由于我无法将它们全部放在一个 then 中的正确位置(我怎么知道哪个响应在哪个位置?),我尝试做这样的事情:

let promises = [];

for (let i = 0; i < requests.length; i++) {
    promises.push(
        axios.get(request[i].url, { params: {...} })
            .then(response => {myObject[request[i].saveLocation] = response.data;})
    );
}

axios.all(promises).then(/* use the data */);

但是,这并没有像我预期的那样工作。每个get 之后的then 被执行,但直到then 附加到axios.all 之后才执行。显然这是一个问题,因为我的代码在将数据保存到对象之前尝试使用数据。

有没有办法为每个axios.get 调用单独的then 调用,该调用将在其对应的promise 解决后执行,然后有一个最终的then 仅在all 的承诺已解决,现在要使用已填充对象的数据吗?

【问题讨论】:

标签: javascript promise axios


【解决方案1】:

如果您第二次尝试的行为确实是这样,那么这表明axios 不符合 Promise/A+。 then 回调的返回值必须是满足 then 返回的承诺的值。由于这是您推入数组的承诺,因此只有通过首先执行 then 回调才能知道axios.all 将为该承诺返回的值。

即使您没有在 then 回调中显式返回值,这也不会影响上述规则:在这种情况下,返回值是 undefined,并且它是 那个 值一旦相应的承诺得到解决,应该由axios.all 提供。

具体参见规则 2.2.7、2.2.7.1、2.3.2.1、2.3.2.2 in the specs of Promise/A+

2.2.7 then 必须返回一个承诺。

promise2 = promise1.then(onFulfilled, onRejected);

2.2.7.1 如果onFulfilledonRejected 返回值x,则运行承诺解决过程[[Resolve]](promise2, x)

[...]

要运行[[Resolve]](promise, x),请执行以下步骤:

[...]

2.3.2 如果x 是一个promise,采用它的状态:

2.3.2.1 如果x 处于待处理状态,则promise 必须保持待处理状态,直到x 被满足或拒绝。

2.3.2.2 如果/当满足x 时,使用相同的值满足promise

所以我建议改用符合 Promise/A+ 的 Promise 实现。还有其他几个库,例如 request-promise

或者,您可以使用本机 ES6 Promise 实现,并自己使用promisify the http.request method

ES6 提供Promise.all,它保证以与提供承诺相同的顺序提供解析值。

【讨论】:

  • 有趣。我找到了在每个get 之后添加then 的方法,但我感谢您的回复。现在,axios 的行为似乎更奇怪了。
【解决方案2】:

好的,所以我找到了一种方法来做我需要的事情,而无需在每个 get 上使用 then。由于传递给axios.get 的参数包含足够的信息来确定保存位置,并且由于我可以从响应中读取参数,因此我可以执行以下操作:

let promises = [];

for (let i = 0; i < requests.length; i++) {
    promises.push(axios.get(request[i].url, { params: {...} }));
}

axios.all(promises)
    .then(axios.spread((...args) => {
        for (let i = 0; i < args.length; i++) {
            myObject[args[i].config.params.saveLocation] = args[i].data;
        }
    }))
    .then(/* use the data */);

这可确保在使用之前接收到所有数据并将其保存到对象中。

【讨论】:

    【解决方案3】:

    如果您将 Promise 传递给附加了它们各自的 then 函数的数组,您的初始代码可以按预期正常工作

    let promises = []; // array to hold all requests promises with their then
    for (let i = 0; i < requests.length; i++) {
        // adding every request to the array
        promises.push(
            axios.get(request[i].url, { params: { ...} })
                .then(response => { myObject[request[i].saveLocation] = response.data; })
        );
    }
    // Resolving requests with their callbacks before procedding to the last then callback
    axios.all(promises).then(/* use the data */);
    

    【讨论】:

    • 您的代码块与问题中的代码块基本相同。只是 cmets 和间距不同。
    • 没错,我只是想将 cmets 添加到他的代码中,以便在运行承诺时向他展示。
    【解决方案4】:

    似乎在这个帖子日,axios 建议使用 Promise.all 而不是 axios.all https://github.com/axios/axios 这对我有用,使用 Nuxtjs

    async nuxtServerInit(vuexContext, context) {
        console.log(context);
    
        const primaryMenuData = {
          query: `query GET_MENU($id: ID!) {
            menu(id: $id, idType: NAME) {
              count
              id
              databaseId
              slug
              name
              menuItems {
                edges {
                  node {
                    url
                    label
                    target
                  }
                }
              }
            }
          }`,
          variables: {
            "id": "Primary"
          }
        }
    
        const primaryMenuOptions = {
          method: 'POST',
          headers: { 'content-type': 'application/json' },
          data: primaryMenuData,
          url: 'http://localhost/graphql'
        };
    
        const postsData = {
          query: `query GET_POSTS($first: Int) {
            posts(first: $first) {
              edges {
                node {
                  postId
                  title
                  date
                  excerpt
                  slug
                  author {
                    node {
                      name
                    }
                  }
                  featuredImage {
                    node {
                      altText
                      caption
                      sourceUrl(size: MEDIUM)
                    }
                  }
                }
              }
            }
          }`,
          variables: {
            "first": 15
          }
        }
    
        const postsOptions = {
          method: 'POST',
          headers: { 'content-type': 'application/json' },
          data: postsData,
          url: 'http://localhost/graphql'
        };
            
        try {
          const [primaryMenuResponse, postsResponse] = await Promise.all([
            await axios(primaryMenuOptions),
            await axios(postsOptions)
          ])
          
          vuexContext.commit('setPrimaryMenu', primaryMenuResponse.data.data.menu.menuItems.edges);
          vuexContext.commit('setPosts', postsResponse.data.data.posts.edges);
    
        } catch (error) {
          console.error(error);
        }      
      },
    

    【讨论】:

      猜你喜欢
      • 2019-07-09
      • 2015-01-14
      • 1970-01-01
      • 1970-01-01
      • 2015-07-25
      • 2017-12-05
      • 1970-01-01
      • 2019-02-20
      • 1970-01-01
      相关资源
      最近更新 更多