如何同时发送多个Axios请求?

47

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

但是,结果似乎是一个接一个地返回,而不是同时返回的。假设对PHP脚本进行一次POST调用需要4秒,并且我需要进行10个调用。 目前每个调用需要4秒,总共需要40秒。我希望找到一个解决方案,以便同时(约为4秒)接收所有结果,而不是~40秒。

现在我已经了解了关于线程、在NodeJS使用Workers进行多线程编程的知识。我已经了解到JavaScript本身只能单线程运行,因此可能无法实现这一点。

但是我不确定从哪里开始。我只有一些想法。我不确定我是否朝着正确的方向前进,如果是,我不确定如何在我的代码中使用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 - Christos Lytras
请参考以下链接: https://www.storyblok.com/tp/how-to-send-multiple-requests-using-axios 这肯定会有所帮助。 - Pallav Chanana
为什么你必须进行多次调用?为什么不能只发起一个POST请求,将所有内容都放在请求体中? 你有权限从后端更改代码吗? - Nafeo Alam
7个回答

85

您可以通过三种方式实现您的目标。

  1. For simultaneous requests with Axios, you can use 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. you can use Promise.allSettled(). The Promise.allSettled() method returns a promise that resolves after all of the given promises have either resolved or rejected,

  3. You can try to use Promise.all() but it has the drawback that if any 1 req failed then it will fail for all and give o/p as an error(or in catch block)

但最好的情况是第一个。


12
дјјд№Ћaxios.allе·Із»Џиў«ејѓз”Ёдє†гЂ‚ж–‡жЎЈдё­жЊ‡е‡є: "иЇ·дЅїз”ЁPromise.allиї›иЎЊж›їжЌў"гЂ‚https://github.com/axios/axios#concurrency-deprecated - gl03

22

你可以使用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已经resolve或reject时解决,具有描述每个Promise结果的对象数组。


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'));

1
我认为这个更好,因为它更容易理解,而且你使用了一个已知的原则:Promise,通过promise.all。 - Bill Somen

3

尝试这种方式

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.
  })

1
当axios调用在循环中时,如何实现它? - Z0q
这个解决方案可以使所有响应同时返回,但加载时间不少于逐个执行。 - Z0q

3

尝试使用Axios.all

  • Use Promise.all() method returns a single Promise that fulfills when all of the promises passed as an iterable have been fulfilled 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);
    })
    

参考链接

点击此处查看axios的完整示例


1
您可以使用这种方式。
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
    }
  });

0

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

Web 浏览器对每个服务器的连接数有限制(在 Chrome 中为 6 https://bugs.chromium.org/p/chromium/issues/detail?id=12066),这可能会解释一些串行化。但不是这种情况。

由于请求需要 4 秒钟,这很,我猜测问题出在服务器上。它可能只能一次处理一个连接。您对其有控制吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接