44

At this moment I have a webpage in which a long list of Axios POST calls are being made. Now, the requests seem to be sent in parallel (JavaScript continues sending the next request before the result is received).

However, the results seem to be returned one by one, not simultaneously. Let's say one POST call to the PHP script takes 4 seconds and I need to make 10 calls. It would currently take 4 seconds per call, which would be 40 seconds in total. I hope to find a solution to both and receive all results at approximately the same time (~4 seconds) instead of ~40 seconds.

Now I've read about threads, multithreading in NodeJS using Workers. I've read that JavaScript itself is only single-threaded, so it may not allow this by itself.

But I'm not sure where to go from here. All I have are some ideas. I'm not sure whether or not I'm heading into the right direction and if I am, I am not sure how to use Workers in NodeJS and apply it in my code. Which road should I take? Any guidance would be highly appreciated!

Here is a small piece of example code:

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!' );
}
Z0q
  • 1,689
  • 3
  • 28
  • 57
  • This is a browser limitation and not specific related to Axios. You can try it even with plain `XMLHttpRequest` and you'll get the same results: [sb-axios-xhr-conccurent](https://stackblitz.com/edit/sb-axios-xhr-conccurent?file=index.js). – Christos Lytras Apr 28 '20 at 11:35
  • Refer this link https://www.storyblok.com/tp/how-to-send-multiple-requests-using-axios this will surely help. – Pallav Chanana Apr 28 '20 at 13:20
  • Why do you have to make multiple calls? Why can't you just make one POST request taking everything in the request body? Do you have the privilege to change the code from backend? – Nafeo Alam May 04 '20 at 18:17

7 Answers7

83

There are three cases via you can achieve your goal.

  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)

but the best case is the first one.

Ashesh
  • 3,499
  • 1
  • 27
  • 44
Harsh Patel
  • 6,334
  • 10
  • 40
  • 73
  • 12
    seems like `axios.all` is deprecated. docs state: "Please use `Promise.all` to replace". https://github.com/axios/axios#concurrency-deprecated – gl03 Dec 09 '21 at 10:08
22

For simultaneous requests with Axios you can use 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');
}));

Also, you can use Promise.all(). Works similar:

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

But, with Promise.all() there is a specific behavior. In case at least one request will be rejected - the all request will be rejected and code will go to .catch() sections. It's OK in case you need to be sure that all requests are resolved.

In case when it's OK when some of your requests are rejected consider using Promise.allSettled(). The Promise.allSettled() method returns a promise that resolves after all of the given promises have either resolved or rejected, with an array of objects that each describes the outcome of each promise.

Maksym Rudnyi
  • 443
  • 3
  • 7
4

If you want to have it within a loop, you can have slightly modified version of @deelink as below

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'));
Rajesh
  • 934
  • 12
  • 23
  • 1
    I think this one is better as its the easier to understand and you're using a known principle : Promise, with promise.all – Bill Somen Aug 09 '20 at 20:37
3

Try in this way

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.
  })
dellink
  • 544
  • 3
  • 16
  • 1
    How do I implement this when axios calls are in a loop? – Z0q Apr 28 '20 at 07:34
  • This solutions makes all responses return at once, but the loading time is not less than executing these one by one – Z0q Apr 28 '20 at 08:41
3

Try this with Axios.all and

  • 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);
    })
    

Ref Link

Find full example here for axios

Pallav Chanana
  • 617
  • 5
  • 10
1

You can use this way

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
    }
  });
Siddhartha Mukherjee
  • 2,703
  • 2
  • 24
  • 29
0

This is weird and shouldn't happen. The Javascript engines are single threaded but the Web APIs (which are internally used when making AJAX requests) are not. So the requests should be made approximately at the same time and the response times should depend on server processing times and network delays.

Web browsers have a limit on the number of connections per server (6 in chrome https://bugs.chromium.org/p/chromium/issues/detail?id=12066) which would explain some serialization. But not this.

Since the requests takes 4 seconds, which is long, my guess is that the server is the problem. It may only be able to handle 1 connection at a time. Do you have control over it?

xabitrigo
  • 1,341
  • 11
  • 24