1

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
 }
vijar
  • 733
  • 4
  • 14
  • 23
  • Well you are better off not using each... – epascarello Jan 28 '14 at 19:38
  • @epascarello will using "for" solve this problem? – vijar Jan 28 '14 at 19:39
  • `each` is not built for what you want, but the functions mentioned on the question I linked as a duplicate all do what you need. And, when we get into the next version of Javascript, [such mechanisms will be a native part of the language](http://www.html5rocks.com/en/tutorials/es6/promises/) – Scott Mermelstein Jan 28 '14 at 19:40
  • @ScottMermelstein I don't know if I'd agree with that duplicate. The solution proposed there is not relevant for server IO. – Peter Jan 28 '14 at 19:54
  • @Peter That was sloppy of me. You're right, the duplicate I posted didn't help enough. – Scott Mermelstein Jan 28 '14 at 21:17
  • http://stackoverflow.com/questions/4869609/how-can-jquery-deferred-be-used is more of what I was thinking of. You want a deferral mechanism. – Scott Mermelstein Jan 28 '14 at 21:19

4 Answers4

1

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
}
Mehran Hatami
  • 12,723
  • 6
  • 28
  • 35
0

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();
gtournie
  • 4,143
  • 1
  • 21
  • 22
  • -1 Doesn't solve the problem asked by OP. This doesn't wait for the server IO to complete before requesting the next. – Peter Jan 28 '14 at 19:49
  • I thought the callback was located the line after getfromserver. I edited my answer. – gtournie Jan 28 '14 at 20:16
0

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.

epascarello
  • 204,599
  • 20
  • 195
  • 236
0

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/

datashaman
  • 8,301
  • 3
  • 22
  • 29