【问题标题】:How to post multiple Axios requests at the same time?如何同时发布多个axios请求?
【发布时间】:2020-08-06 16:10:23
【问题描述】:

此时,我有一个网页,其中正在执行一长串 Axios POST 调用。现在,请求似乎是并行发送的(JavaScript 在收到结果之前继续发送下一个请求)。

但是,结果似乎是一个一个返回,而不是同时返回。假设对 PHP 脚本的一次 POST 调用需要 4 秒,而我需要进行 10 次调用。目前每次调用需要 4 秒,总共需要 40 秒。我希望找到解决这两个问题的方法,并在大约同一时间(约 4 秒)而不是约 40 秒收到所有结果。

现在我已经阅读了关于线程,NodeJS 中使用 Workers 的多线程。我读过 JavaScript 本身只是单线程的,所以它本身可能不允许这样做。

但我不知道从这里去哪里。我所拥有的只是一些想法。我不确定我是否朝着正确的方向前进,如果是,我不确定如何在 NodeJS 中使用 Workers 并将其应用到我的代码中。我应该走哪条路?任何指导将不胜感激!

这是一小段示例代码:

for( var i = 0;  i < 10;  i++ )
{
    window.axios.post(`/my-url`, {
        myVar: 'myValue'
    })
    .then((response) => {
        // Takes 4 seconds, 4 more seconds, 4 more seconds, etc
        // Ideally: Takes 4 seconds, returns in the same ~4 seconds, returns in the same ~4 seconds, etc
        console.log( 'Succeeded!' );
    })
    .catch((error) => {
        console.log( 'Error' );
    });

    // Takes < 1 second, < 1 more second, < 1 more second, etc
    console.log( 'Request sent!' );
}

【问题讨论】:

  • 这是浏览器限制,与 Axios 无关。即使使用普通的XMLHttpRequest,您也可以尝试它,您会得到相同的结果:sb-axios-xhr-conccurent
  • 参考此链接storyblok.com/tp/how-to-send-multiple-requests-using-axios 这肯定会有所帮助。
  • 为什么要打多个电话?为什么你不能只发出一个 POST 请求来获取请求正文中的所有内容?您是否有权从后端更改代码?

标签: javascript node.js multithreading axios


【解决方案1】:

你可以通过三种情况来实现你的目标。

  1. 对于与 Axios 的并发请求,您可以使用Axios.all()

     axios.all([
       axios.post(`/my-url`, {
         myVar: 'myValue'
       }), 
       axios.post(`/my-url2`, {
         myVar: 'myValue'
       })
     ])
     .then(axios.spread((data1, data2) => {
       // output of req.
       console.log('data1', data1, 'data2', data2)
     }));
    
  2. 您可以使用Promise.allSettled()。 Promise.allSettled() 方法返回一个在所有给定的 Promise 都已解决或被拒绝后才解决的 Promise,

  3. 您可以尝试使用Promise.all(),但它的缺点是如果任何 1 req 失败,那么它将全部失败并将 o/p 作为错误(或在 catch 块中)

但最好的情况是第一个。

【讨论】:

【解决方案2】:

对于与 Axios 的并发请求,您可以使用 Axios.all()。

axios.all([
  axios.get('https://api.github.com/users/MaksymRudnyi'), 
  axios.get('https://api.github.com/users/taylorotwell')
])
.then(axios.spread((obj1, obj2) => {
  // Both requests are now complete
  console.log(obj1.data.login + ' has ' + obj1.data.public_repos + ' public repos on GitHub');
  console.log(obj2.data.login + ' has ' + obj2.data.public_repos + ' public repos on GitHub');
}));

另外,您可以使用 Promise.all()。工作类似:

Promise.all([
  fetch('https://api.github.com/users/MaksymRudnyi'),
  fetch('https://api.github.com/users/taylorotwell')
])
.then(async([res1, res2]) => {
  const a = await res1.json();
  const b = await res2.json();
  console.log(a.login + ' has ' + a.public_repos + ' public repos on GitHub');
  console.log(b.login + ' has ' + b.public_repos + ' public repos on GitHub');
})
.catch(error => {
  console.log(error);
});

但是,使用 Promise.all() 有一个特定的行为。如果至少一个请求将被拒绝 - 所有请求都将被拒绝,代码将转到 .catch() 部分。万一您需要确保所有请求都已解决,也可以。

如果您的某些请求被拒绝时可以考虑使用 Promise.allSettled()。 Promise.allSettled() 方法返回一个在所有给定的 Promise 都已解决或被拒绝后解决的 Promise,并带有一组对象,每个对象都描述每个 Promise 的结果。

【讨论】:

    【解决方案3】:

    用 Axios.all 试试这个

    • 使用 Promise.all() 方法返回一个 Promise,当所有作为 iterable 传递的 Promise 都已实现时,该 Promise 已实现 Promise MDN ref Link

      import axios from 'axios';
      let one = "https://api1"
      let two = "https://api2"
      let three = "https://api3"
      
      const requestOne = axios.get(one);
      const requestTwo = axios.get(two);
      const requestThree = axios.get(three);
      
      axios.all([requestOne, requestTwo, requestThree]).then(axios.spread((...responses) => {
        const responseOne = responses[0]
        const responseTwo = responses[1]
        const responesThree = responses[2]
        // use/access the results 
      console.log("responseOne",responseOne);
      console.log("responseTwo",responseTwo);
      console.log("responesThree",responesThree);
      })).catch(errors => {
        console.log(errors);
      })
      

    参考链接

    Find full example here for axios

    【讨论】:

      【解决方案4】:

      这样试试

      window.axios.all([requestOne, requestTwo, requestThree])
        .then(axios.spread((...responses) => {
          const responseOne = responses[0]
          const responseTwo = responses[1]
          const responesThree = responses[2]
          // use/access the results 
        })).catch(errors => {
          // react on errors.
        })
      

      【讨论】:

      • axios调用循环时如何实现?
      • 这个解决方案让所有响应一次返回,但是加载时间不小于一个一个执行这些
      【解决方案5】:

      如果你想在循环中使用它,你可以稍微修改一下@deelink 的版本,如下所示

      let promises = [];
      for (i = 0; i < 10; i++) {
        promises.push(
          window.axios.post(`/my-url`, {
          myVar: 'myValue'})
         .then(response => {
            // do something with response
          })
        )
      }
      
      Promise.all(promises).then(() => console.log('all done'));
      

      【讨论】:

      • 我认为这个更好,因为它更容易理解,并且您使用的是已知原则:Promise, with promise.all
      【解决方案6】:

      这很奇怪,不应该发生。 Javascript 引擎是单线程的,但 Web API(在发出 AJAX 请求时在内部使用)不是。因此,请求应大致同时发出,响应时间应取决于服务器处理时间和网络延迟。

      Web 浏览器对每台服务器的连接数有限制(chrome https://bugs.chromium.org/p/chromium/issues/detail?id=12066 中的连接数为 6),这可以解释一些序列化。但不是这个。

      由于请求需要 4 秒,即 long,我的猜测是服务器是问题所在。它可能一次只能处理 1 个连接。你能控制它吗?

      【讨论】:

        【解决方案7】:

        你可以这样使用

        const token_config = {
         headers: {
            'Authorization': `Bearer ${process.env.JWD_TOKEN}`
           }
         }
        
        const [ res1, res2 ] =  await Axios.all([
            Axios.get(`https://api-1`, token_config), 
            Axios.get(`https://api-2`, token_config)
          ]);
        
          res.json({
            info: {
              "res_1": res1,
              "res_2": res2
            }
          });
        

        【讨论】:

          猜你喜欢
          • 2022-12-10
          • 2021-11-19
          • 1970-01-01
          • 1970-01-01
          • 2020-07-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-02-25
          相关资源
          最近更新 更多