0

I created a for loop and runs Javascript(jquery)code in it. But somehow the for loop variable increments automatically.

for (var i=0; i<len; i++) {    //len=2
        console.log(i);  // outputs 0 and 1 as expected 
        $.ajax({
        url:'execute.php',
        method:'GET',
        data:{
            link: items[i]
        },

        success:function(data){
            console.log(i);       //outputs 2 and 2. It sould be 0 and 1
            $("#div1").html(data);
            var item = $(".sticky-item-title .title").html();
            $("#product-"+ i).html(item);
        },
        error:function(data){
            alert('error' + data);
        }
    });
}

The console.log before $.ajax shows 0 and 1 as expected (I have 2 items in len). But the console.log inside success function shows as 2 and 2. Why and where is it incremented. I tried this code

for (var i=0; i<len; i++) {
        var s=i;
        $.ajax({
        url:'execute.php',
        method:'GET',
        data:{
            link: items[s]
        },

        success:function(data){
            console.log(s);          //outputs 1 and 1. It should be 0 and 1 
            $("#div1").html(data);
            var item = $(".sticky-item-title .title").html();
            $("#product-"+ s).html(item);
        },
        error:function(data){
            alert('error' + data);
        }
    });
}

Here the variable s show 1 and 1 instead of 0 and 1.

What am I doing wrong here. Thanks in advance

Andreas
  • 23,610
  • 6
  • 30
  • 62
Abdulla
  • 441
  • 1
  • 9
  • 21
  • 1
    read this https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example and this https://stackoverflow.com/questions/11488014/asynchronous-process-inside-a-javascript-for-loop – ashish singh Oct 16 '18 at 17:06
  • Use `let` instead of `var`. – ssc-hrep3 Oct 16 '18 at 17:07
  • 1
    Possible duplicate of [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – rlemon Oct 16 '18 at 17:09
  • Possible duplicate of [Asynchronous Process inside a javascript for loop](https://stackoverflow.com/questions/11488014/asynchronous-process-inside-a-javascript-for-loop) – aynber Oct 16 '18 at 17:10
  • For your question on why it is `2`: `i++` is exectued as long as `i < len`. As `1` is smaller then `len` (`2`) the `i++` part is executed (-> `i === 2`) and only then the condition `i < len` is `false` and the loop stops. – Andreas Oct 16 '18 at 17:17
  • using let instead of var solved it. But now the problem is when I refresh, sometimes, it displays correctly, but sometimes only 1 or 0 is shown not both. Is it because of the response time of the ajax request? any solutions for that? – Abdulla Oct 16 '18 at 18:50

2 Answers2

1

When you use var to define a variable, you are only declaring a single variable, which is overwritten in each loop. In the asynchronous callback after the loop, the variable is then the value of the last iteration. You can circumvent this by using let or by definining a self invoking function, passing the iterating value as a parameter.

for (let i = 0; i < array.length; i++) { ... }

or

for (var i = 0; i < array.length; i++) {
   (function(i) {
   ...
   })(i);
}
ssc-hrep3
  • 15,024
  • 7
  • 48
  • 87
  • That's the really short answer to an unasked problem (which has two very distinct duplicates already linked in the comments, hence this should be closed as such), but the question: _"...inside success function shows as 2 and 2. **Why and where is it incremented**"_ is still unanswered. – Andreas Oct 16 '18 at 17:13
0

Ajax works in asynchronous manner, so the name (A)synchronous (JA)vascript and (X)ml. The method you are declaring in Ajax for success/error are just callback method references you are passing to the Ajax function. They are not called at the time the Ajax request is sent out. They are called once the response is received or not received(timeout or bad response) from the server.

What is happening in your code is that after the request is sent out, we are not receiving the response that vary moment. We are getting the response after the loop has run the second time and the var 'i' has been incremented to 2, i.e. the final value where the loop condition will be false. The browser engine receive the response of the Ajax request it then call the success or error function depending on the response. By that time, the value of 'i' variable has already been set to 2 because of which the console prints '2'.

If you want your code to print the value of the loop then you can pass the value in the function declaration as custom property like:

for (var i=0; i<len; i++) {
    console.log(i);
    $.ajax({
    url:'execute.php',
    method:'GET',
    indexVal:i,
    data:{
        link: items[i]
    },

    success:function(data){
        console.log(this.indexVal);
        $("#div1").html(data);
        var item = $(".sticky-item-title .title").html();
        $("#product-"+this.indexVal).html(item);
    },
    error:function(data){
        alert('error' + data);
    }
});

}

I did not test the code, but this should work. Please let me know if it works for you in comments.

Akshay Mishra
  • 189
  • 1
  • 8