0

I'm running into a small issue while trying to loop asynchronous events. In my case I was trying to shorten the amount of typing done to send 5 different AJAX request to the server, where as the only difference in the request is an ID which should always be 1-5.

Below is my code showing this, please note that I am using AngularJS so I'm using their post method.

function loopRequest($http, destination) {
    for(var i = 1; i < 6; i++) {
        // Attempt to preserve the value of i throughout the asynchronous call
        var tmp = i; 

        $http.post("http://localhost/test.php", {slot: tmp}).success(function(data) {
            console.log("AJAX call completed for ID: " + tmp);
        });
    }
}

The result of this execution is the following:

AJAX call completed for ID: 5
AJAX call completed for ID: 5
AJAX call completed for ID: 5
AJAX call completed for ID: 5
AJAX call completed for ID: 5

Obviously I could send the identification number back with the AJAX call however I don't want to do that and would rather understand what the issue is here before continuing. I understand that the array is continuing before the asynchronous function completes, however in java defining a temporary variable like done above would stay in scope for the remainder of the array's cycle and be used by the asynchrnous call. Apparently that doesn't work here.

What should I be doing? I could just write out 5 different calls here, but the idea was to eliminate the need to do so.

Hobbyist
  • 15,888
  • 9
  • 46
  • 98
  • 2
    AJAX call are async and when the results are returned from server at that time the value of tmp is 5. – Braj Jul 29 '15 at 08:41
  • The main idea is _a function uses that scope which this function was initialized with_, so all callbacks use the same _tmp_, it's pretty clear. And since _$http.post()_ is asynchronos there, _for loop_ will not wait for call of callback. And when callback funtion will be called, you it will has _tmp = 5_ in it's scope. Thus you will have same logs. Here is some examples of preventing this kind of behavior. It's with _setTimeout_ function, but maybe it will be usefull for you [jsfiddle](http://jsfiddle.net/Lends/ybavwr1m/4/) – Ivan Jul 29 '15 at 09:06

3 Answers3

4

The reason is function scope. Since you have wrapped your tmp variable outside of your $.post functions callback it will allways have the reference to the scope of the outer function.

try wrapping your request into a different function passing the tmp variable as a parameter

myPostfunction(tmp);

so you always have an individual function scope for each request

EDIT 1:

example

function loopRequest($http, destination) {
    for(var i = 1; i < 6; i++) {
        myPostfunction(i);
    }
}

function myPostfunction(tmp){
       $http.post("http://localhost/test.php", {slot: tmp}).success(function(data) {
            console.log("AJAX call completed for ID: " + tmp);
        });
}
Max Bumaye
  • 1,017
  • 10
  • 17
3

My favourite way of dealing with this is IIFE, as it doesn't change the code "flow" as much as defining a function and calling it

function loopRequest($http, destination) {
    for(var i = 1; i < 6; i++) {
        // Attempt to preserve the value of i throughout the asynchronous call

        (function(captured_i) {
            $http.post("http://localhost/test.php", {slot: captured_i}).success(function(data) {
                console.log("AJAX call completed for ID: " + captured_i);
            });
        }(i));
    }
}
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • @MaxBumaye - I agree it can look more complicated to a novice, but when you use it every day it just makes mode sense - at least to me – Jaromanda X Jul 29 '15 at 09:03
  • It does make sense and I also read it and see the beauty in it. But it gets kind of unclean... but as I said its a matter of style and just a short sidenote :) – Max Bumaye Jul 29 '15 at 09:05
  • Very straightforward and simple, I had no idea you could wrap functions like this. – Hobbyist Jul 29 '15 at 14:29
0

Do this one:

function loopRequest($http, destination) {
    for(var i = 1; i < 6; i++) {
        // Attempt to preserve the value of i throughout the asynchronous call 
        doAjax(i);
    }
}

function doAjax(tmp){
       $http.post("http://localhost/test.php", {slot: tmp}).success(function(data) {
            console.log("AJAX call completed for ID: " + tmp);
        });
}

Here value of i will be copied to doAjax function. In your scenario, your i value has been incremented up to 5, before all function s had finished. that is why tmp is 5 at the end.

If you wrap ajax in a function, than i value will be copied to it.

Beri
  • 11,470
  • 4
  • 35
  • 57