2

I have not been able to resolve this, and I have found many similar examples but nothing really seems to work or apply to my situation.

My code is as follows

$.each(versions, function(key,value) {
    progressText.html("Downloading Version " + value);
    ajaxUpdate('download',value).then(console.log(value));
});

function ajaxUpdate(step,value) {
    return $.ajax({
        url: 'action/' + step + '.update/',
        data: 'version=' + value
    })
}

Basically my problem is it does the each simultaneously, I want it to finish one each, then go onto the next.

How would I go about that?

Chris James Champeau
  • 984
  • 2
  • 16
  • 37

2 Answers2

5

You can use jQuery.Deferred() object to make ajax requests one by one. If you want to call some function after all request completed, use deffer.then(...) after each loop:

function ajaxUpdate(step,value) {
    return $.ajax({
        url: 'action/' + step + '.update/',
        data: 'version=' + value
    })
}

// Emulate resolved deferred to be able to chain to it in each loop
var defer = $.Deferred().resolve();

$.each(versions, function(key, value) {
  // Add next deferred to chain, it will be invoked when previous is completed
  defer = defer.then(function(){
    return ajaxUpdate('download', value)
  });
});

defer.then(function(){
    console.log('All requests completed')
})

Example with timeout

var $log = $('#log');

function ajaxUpdate(url, step) {
  return $.Deferred(function() {

    setTimeout(function() {
      $log.append('<p>finished:' + step + '</p>')
      this.resolve();
    }.bind(this), Math.random() * 1000)

  })
}

var defer = $.Deferred().resolve();
var versions = [1, 2, 3, 4, 5];

$.each(versions, function(key, value) {
  defer = defer.then(function() {
    return ajaxUpdate('download', value)
  });
});

defer.then(function() {
  $log.append('<p>All Done</p>')
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="log"></div>
t1m0n
  • 3,413
  • 1
  • 17
  • 21
0

I had a similar problem that I posted here, JQuery - Looping a .load() inside a 'for' statement and the solution that worked for me, and I think could work for you, since if I read correctly, you want it to do one at a time, was to use a recursive function.

The reason it doesn't work right now is because Ajax performs an asynchronous request, so your code is executed all at once, since your browser doesn't have to wait the request to be finished before moving on to the next one. What you're gonna have to do is force it to wait for it to finish before moving on to it's next task. You do this, as previously said, with a recursive function. Basically your make a function that calls itself only when your request is finally done.

Of course mine used a simple For statement, and not a .each loop. After looking through for a while I found this example of someone wanting to use a recursive function on a .each loop: jQuery recursive iteration over objects

So your code should look like this:

 $.each(versions, function(key,value) { recursiveFunction(key, val) });

function recursiveFunction(key, val) {
    progressText.html("Downloading Version " + value);
    function ajaxUpdate(key,val) {
    $.ajax({
      url: 'action/' + step + '.update/',
      data: 'version=' + value
      }).done(function(data) {
            console.log(value);
            recursiveFunction(key, val);
        });
      }

}

The code might need a little cleaning up, since I can't for the life of me get used to the stack Overflow code editor, and I might need some more of your code for context on what you're exactly trying to do and how, but in essence it should be something like that. It should work, if you tweak it a bit c: Also read through the links I included here, they should help you understand what I'm trying to convey here.

Community
  • 1
  • 1
Miguel Guerreiro
  • 356
  • 1
  • 2
  • 11