jQuery: wait for function to complete to continue processing?
Asked Answered
O

9

17

Hey all. I have, what appears to be, a trivial problem. I have the following JavaScript:

$(function() {
    var r = GetResults();

    for(var i = 0; i < r.length; i++) {
        // Do stuff with r
    }
});

function GetResults() {
   $.getJSON("/controller/method/", null, function(data) {
       return data;
   });
}

Due to the fact that I'm calling a method asynchronously, the script continues executing and when it encounters the for loop, r obviously isn't going to have a value yet. My question is: when I have a method that is doing an asynchronous operation, and I'm dependent on the data it returns back in the main block, how do I halt execution until the data is returned? Something like:

var r = GetResults(param, function() {

});

where the function is a callback function. I cannot move the for loop processing into the callback function of the JSON request because I am reusing the functionality of GetResults several time throughout the page, unless I want to duplicate the code. Any ideas?

Ohl answered 21/9, 2009 at 17:54 Comment(0)
S
13

move your "do stuff with r" block into your $.getJSON callback. you can't do stuff with r until it has been delivered, and the first opportunity you'll have to use r is in the callback... so do it then.

$(function() {
    var r = GetResults();  
});

function GetResults() {
   $.getJSON("/controller/method/", null, function(data) {
       for(var i = 0; i < data.length; i++) {
           // Do stuff with data
       }
       return data;
   });
}
Shive answered 21/9, 2009 at 17:58 Comment(2)
Thank you for the response. The reason I split GetResults out was that I am reusing that functionality several times throughout the page. I should edit my post to state that.Ohl
if you need to do the same processing on data coming from multiple places, just replace your callback function with a named function and do the processing there. $.getJSON("/controller/method/", null, processData(data)); function processData(d) { ... }Shive
F
8

I've run into something similar before. You'll have to run the ajax call synchronously.

Here is my working example:

$.ajax({
    type: "POST",
    url: "/services/GetResources",
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    data: '{resourceFileName:"mapedit",culture:"' + $("#lang-name").val() + '"}',
    cache: true,
    async: false, // to set local variable
    success: function(data) {
        localizations = data.d;
    }
});
Folksy answered 21/9, 2009 at 18:39 Comment(2)
This certainly works, but it blocks the UI thread, doesn't it? (Perhaps that's acceptable, though it doesn't seem necessary given the information we have so far.)Perpetual
Yes, it does block, but of course only for the duration of the request. I don't see any other way around it, given what you're looking for. I went down the same road and went the sync route.Folksy
P
7

Ajax already gives you a callback, you are supposed to use it:

function dostuff( data ) {
    for(var i = 0; i < data.length; i++) {
        // Do stuff with data
    }
};
$(document).ready( function() {
    $.getJSON( "/controller/method/", null, dostuff );
});
Percolator answered 21/9, 2009 at 17:59 Comment(0)
S
3

You could do this:

$(function() {
    PerformCall();        
});

function PerformCall() {
   $.getJSON("/controller/method/", null, function(data) {
       for(var i = 0; i < data.length; i++) {
        // Do stuff with data
       }
   });
}
Scrutator answered 21/9, 2009 at 17:58 Comment(0)
G
2

The short answer is that you can't block on an asynchronous operation...which is of course, the meaning of "asynchronous".

Instead, you need to change your code to use a callback to trigger the action based on the data returned from the $.getJSON(...) call. Something like the following should work:

$(function() {
  GetResults();
});

function GetResults() {
  $.getJSON("/controller/method/", null, function(data) {
    for(var i = 0; i < data.length; i++) {
      // Do stuff with data
    }
  });
}
Grigg answered 21/9, 2009 at 18:1 Comment(0)
P
2

Given your updated requirements ...

I cannot move the for loop processing into the callback function of the JSON request because I am reusing the functionality of GetResults several time throughout the page, unless I want to duplicate the code. Any ideas?

... you could modify GetResults() to accept a function as a parameter, which you would then execute as your $.getJSON callback (air code warning):

$(function() {
    GetResults(function(data) {
        for(var i = 0; i < data.length; i++) {
            // Do stuff with data
        }
    });
});

function GetResults(callback) {
   $.getJSON("/controller/method/", null, callback);
}

As you can see from the general tide of answers, you're best off not trying to fight the asynchronous jQuery programming model. :)

Perpetual answered 21/9, 2009 at 18:10 Comment(0)
M
0

This is not possible.

Either you make your function synchronous or you change the design of your code to support the asynchronous operation.

Marras answered 21/9, 2009 at 17:58 Comment(0)
M
0

Move the data processing into the callback:

$(function() {
    GetResults();
});

function GetResults() {
   $.getJSON("/controller/method/", null, function(data) {

       for(var i = 0; i < data.length; i++) {
           // Do stuff with data
       }
   });
}
Multivocal answered 21/9, 2009 at 17:59 Comment(2)
this wont work. your return statement will return from the callback, not from GetResults. This solution will never work as it does not use callbacks properlyClinkscales
@Clinkscales Thanks. I've removed the return from the callback.Multivocal
K
0

You can have a callback with parameters that should work nicely...

$(function() {
    GetResults(function(data) {
      for(var i = 0; i < data.length; i++) {
        // Do stuff with data
      }
    });

});

function GetResults(func) {
   $.getJSON("/controller/method/", null, func);
}
Kailyard answered 21/9, 2009 at 18:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.