vijar
vijar

Reputation: 781

How to make Jquery $.each loop wait for operation to complete before iterating?

I have a function that has a $.each to loop over keys of an object and do stuff. within this loop i am calling a function which in turns makes a call to the server to get some data and does things with it in a callback. these calls are asynchronous so the $.each does not wait for the data to come and the callback to do what its supposed to and keeps iterating. How do i make the $.each loop wait till i complete my operation and then continue.

$.each(messages,function(key) {  
//do something 
if(some Condition) {
getfromserver(token,myCallback); }
//do something 
});




function myCallback(data)
 {
   //do something with data
 }

Upvotes: 1

Views: 4069

Answers (4)

datashaman
datashaman

Reputation: 9009

This is in coffeescript, but I think it does what you need. You keep throwing execution forward into a function, much like in nodejs:

processMessages = (messages, callback, args) ->
    # End it by returning the callback result when messages are done
    return callback() unless messages.length

    # Shift the first message off the list
    message = messages.shift()

    # Send it to the server for something to do
    $.ajax
        url: '/echo/json/'
        method: 'POST'
        data:
            json: JSON.stringify({ message: message, args: args })
        dataType: 'json'
        success:(data) ->
            # Respond to the server's response
            console.log 'Got ' + data.message

            # Process the remaining messages
            processMessages messages, callback, args

finished = ->
    console.log 'all done here'

processMessages ['hi', 'bob'], finished, 'yo'

Coffeescript: http://jsfiddle.net/datashaman/22gDa/3/

Javascript fork: http://jsfiddle.net/datashaman/3zdQ8/1/

Upvotes: 0

gtournie
gtournie

Reputation: 4382

You can't with a simple iteration. Instead you should do this:

function unqueue() {
  if (!messages.length)
    return;
  var key =  messages.pop();
  // do something
  getfromserver(token, myCallback);
  //do something
}

function myCallback(data) {
  //do something with data

  // Repeat it until messages is not empty
  unqueue();
}

unqueue();

Upvotes: 0

Mehran Hatami
Mehran Hatami

Reputation: 12961

You can do this instead of $.each, I call it callback loop:

iterate(messages, 0);

function iterate(arr, i) {
    if(i==arr.length) return;
    var message = arr[i];
    //you might want to create your token based on current message
    var token = "...";

    if(/*some Condition*/){
        getfromserver(token, function (data) {
            myCallback(data);
            iterate(arr, i++);
        });
    }
    //use this else if you want to do something like 'continue'
    //and don't use it if it kinda 'break'
    else iterate(arr, i++);
}

function myCallback(data) {
    //do something with data
}

Upvotes: 1

epascarello
epascarello

Reputation: 207501

Basic idea of adding the loop into your callback

var messages = {foo:"1","bar":2,"asdf":3}; 
var keys = $.map(messages, function(val, key) { return key});

function makeCall() {
   if(!keys.length) return;
   var next = keys.shift();
   var token = messages[next];
   getfromserver(token,myCallback);
}

function myCallback(data)
 {
   //do something with data
   makeCall();
 }

There are tons of ways of building up a queue of calls.

Upvotes: 0

Related Questions