0

This is my code:

for (var i = 0; i < 20; i++) {
$.ajax({
    type: "GET",
    async: false,
    url: "/MyController/MyMethod",
    success: function (data) {
        if (i == 0) {
            $('#result_progress').hide();
            $('#result_msg').hide();
            $('#details').show();
        } else if (i == 1) {
            $.ajax({
            type: "GET",
            async: true,
            url: "/Import/Finish",
            success: function (data) {
                    ....                        
            });                                            
        }
        if (i < 2) {
            $('#details').html($('#details').html() + 'someText'));
        }                                        
    }
});

}

I don't want to use async: false because my browser stops working. How would I fix this in another way?

petko_stankoski
  • 10,459
  • 41
  • 127
  • 231

3 Answers3

0

Your problem is that i has the value of end of loop when the callbacks are executed.

The standard solution to fix that is to add an intermediate immediately called function to protect the value of i :

for (var i = 0; i < 20; i++) {
   (function(i){
      ... your code
   })(i);
}

The call to the function creates a scope in which i is a different variable.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • You are right, but that does not appear to be what the OP is asking for ;) – Felix Kling Apr 03 '13 at 12:22
  • @FelixKling I'm not sure. I don't read the question like you (I've seen your other comment). BTW, I don't find the usual question, I would have closed as duplicate. I'm sure you have a link... – Denys Séguret Apr 03 '13 at 12:22
  • Oh now I get it... you think the OP uses `async: false` because of `i`. Maybe you should explicitly mention that setting it to `false` is not needed anymore then. If the OP wanted to run the requests sequentially, I would have searched for some deferred object solution... – Felix Kling Apr 03 '13 at 12:24
  • @FelixKling I made my answer CW. You may complete it. – Denys Séguret Apr 03 '13 at 12:32
  • @dystroy With you solution, MyMethod from the controller is called just once, and the success is entered twice. – petko_stankoski Apr 03 '13 at 12:32
0

I think you should do it with some closure:

function makeReq(n){
   return function(){
      $.ajax({
        type: "GET",
        async: true,
        url: "/MyController/MyMethod",
        success: function (data) {
           if (n == 0) {
              $('#result_progress').hide();
              $('#result_msg').hide();
              $('#details').show();
           } else if (n == 1) {
              $.ajax({
                type: "GET",
                async: true,
                url: "/Import/Finish",
                success: function (data) {
                    ....                        
                });                                            
           }
           if (n < 2) {
               $('#details').html($('#details').html() + 'someText'));
           }                                        
       }
     });
   }
}

for (var i = 0; i < 20; i++) {
    makeReq(i);
}

This problem can be solved by creating a function and calling it on each iteration of the loop, while passing i; calling the function will form a brand new execution context where the value of i is retained and can be used in any way within that context.

Jai
  • 74,255
  • 12
  • 74
  • 103
0

Here's how I fixed it:

function run(i, howManyToRun, start) {
    if(i >= howManyToRun) return;

    $.ajax({
        type: "GET",
        async: false,
        url: "/MyController/MyMethod",
        success: function (data) {        
            ....
            run(++i, howManyToRun, start);
            ....                                    
        }
    });
}
petko_stankoski
  • 10,459
  • 41
  • 127
  • 231