0

Let's say I wanna get some data from 1000 servers. Each server returns the same json structure. Dummy Example:

{
    logins: 5000,
    clicks: 1000
}

Let's say that I need to sum all logins from each server response.

Instead of query all the json and then perform the sum, I would like to do it in every callbacks (= 1000 times). Basic Example:

var result = 0;

$http.get(url).then(function(response) {
    result += response.data.logins;
});

An example to explain why the lock is necessary:

If my first server returns 1000, the second 2000 and the third 3000;

Let's say the second hasn't finished yet when the third callback is called my the promise, for whatever reason.

If there is no lock on result, it will probably equal 4000 at the end of the third callback, which is wrong (the correct value is 6000);

So what do you think guys ? Is the result locked automatically or not ? If not, is it easy to create the lock pattern in js ?

Thanks for your answers !

Vivien Adnot
  • 1,157
  • 3
  • 14
  • 30
  • If the request is successfully all logins counters should be added, sooner or latter no matter the order (as is async request) – aabilio Aug 24 '16 at 09:50
  • Possible duplicate of [Wait until all jQuery Ajax requests are done?](http://stackoverflow.com/questions/3709597/wait-until-all-jquery-ajax-requests-are-done) – Sudsy Aug 24 '16 at 09:53
  • @aabilio Are you sure about that ? Every callback want to add their value to the current result, but the second wants to add its value before the first has finished its task. Before adding the value, the second has to ask the current value of result first. But here is the catch: result is not yet updated with the value of the first callback. So his current value is "wrong". Eventually, the second adds his value to the wrong number and the chain is wrong. Do you agree ? – Vivien Adnot Aug 24 '16 at 09:55
  • @VivienAdnot result will be updated in each success callback, so if you care about the order, you will have problems, but if you just want to have the summation at the end, then is ok, no matter the order.. – aabilio Aug 24 '16 at 09:59
  • "If there is no lock on result, it will probably equal 4000 at the end of the third callback, which is wrong (the correct value is 6000);". But, why is wrong? It is just "wrong" for your approach if you need the order, but if you just need the total, the order should be not care, you can get it even if the responses do not came in the order you've sent – aabilio Aug 24 '16 at 10:19
  • You just change the question. The answer is not Ajax do not care about the order and yes you can force to run Ajax sync, but I do not recommend it, and less with that amount of requests you want send.. If you need order, I will include a flag key order on the server response to and use async ajax.. – aabilio Aug 24 '16 at 10:29
  • @aabilio Thank you for your time and your responses ! I will answer your next post, as you posted some code it's more easy for the other readers than in the comments. See you there ! – Vivien Adnot Aug 24 '16 at 12:33

1 Answers1

1

I update the answer because the question was edited:

If you send many ajax calls requests, responses might not come in order, so if you need the order, you can force the ajax calls to run synchronously (if you use $http from Angular you can't).

But I would never do that (I would always use async), especially because the number of request you want to send...

If you want you can do something like just call the next endpoint on the previous success callback:

$http.get(url).then(function(response) {
    result += response.data.logins;
    $http.get(url).then(function(response) {
        result += response.data.logins;
        /// ... (use a loop)
    });
});

Example:

const data = [
{
  isActive: "1",
  logins: 1000,
  clicks: 1000
},
{
  isActive: "1",
  logins: 2000,
  clicks: 1000
},
{
  isActive: "1",
  logins: 3000,
  clicks: 1000
}];

const callApi = (index, timeout) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve({data: data[index]}), timeout);
  })
};

let result = 0;
let timeouts = [0, 3000, 0];

const callback = (resp, index) => {
  result += resp.data.logins;
  console.log(`Result now in callback ${index + 1}:`, result);
 
  if (index < timeouts.length - 1) {
    index++;
    callApi(index, timeouts[index]).then(resp => callback(resp, index))
  }
  
}

callApi(0, timeouts[0]).then(resp => callback(resp, 0))

Depending on what you want to achieve I would use a key to track the request in the callback even using the server if you need it.

If you only need the sum of all 'logins' counters and you do not need the order

const data = [
{
  isActive: "1",
  logins: 1000,
  clicks: 1000
},
{
  isActive: "1",
  logins: 2000,
  clicks: 1000
},
{
  isActive: "1",
  logins: 3000,
  clicks: 1000
}];

const callApi = (index, timeout) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve({data: data[index]}), timeout);
  }) 
};

let result = 0;
[0, 3000, 0].forEach((timeout, index) => {
  callApi(index, timeout)
    .then(res => {
      result += res.data.logins
      console.log(`Result now in callback ${index + 1}:`, result)
    })
});
aabilio
  • 1,697
  • 12
  • 19
  • Just a quick question: how do you know when all the calls are over and you can return the object result via a callback ? – Vivien Adnot Aug 24 '16 at 14:15
  • @VivienAdnot with the method where you init the following ajax request on the previous success callback: `if (index < timeouts.length - 1) { /*...*/ } else { /*HERE*/ }` – aabilio Aug 25 '16 at 06:46