1

I am using jQuery and currently doing an $.ajax() call inside the $(document).ready() function. However I realized that to do the AJAX call I do not use anything from the DOM. Also that Ajax call might take a second or two (or more) server-side. So, for both those reasons, I'd like to get it going as soon as possible, and I'm thinking to refactor my code to look something like this (this would go in a <script> block near the top of the HTML file):

var someGlobal="whatever";
...
function onReply(response){
  //Do something
}
...
$.ajax({
   'url':"call_me.json",
   'type':'POST',
   'data':{x:someGlobal,y:"Dude!"}
  })
  .fail(function(jqXHR,status){
    console.log("AJAX ERROR:" + status);
    })
  .done(onReply);
...

However, the onReply() callback does need the DOM to have been constructed (ditto for the .fail() callback). So I don't want onReply to be called before $(document).ready() has run. Is there anything built-in to jQuery that allows me to guarantee that will be the case?

P.S. Using jQuery 1.10.x

Darren Cook
  • 27,837
  • 13
  • 117
  • 217
  • Very similar question (once you think to use deferreds): http://stackoverflow.com/questions/6177187/can-i-get-a-jquery-deferred-on-document-ready (but none of the answers consider what happens if the ajax call fails; they also don't start the ajax call until the page has fully loaded, and I want to start it immediately.) – Darren Cook Feb 17 '14 at 12:24

2 Answers2

2

Try this:

var flag = 0;
function onReply(response){
    if (flag == 0)
    {
        $(document).ready(
            function () {
                anotherfunction(response);
            });
    }
    else
        anotherfunction(response);
}

$(document).ready(
    function () {
        flag = 1;
    }
);

function anotherfunction(resp) {
    // Do something
}

Better way (1.5 years later):
Instead of using a variable to track the load status of the document, we can use the javascript's own document.readyState.

function onReply(response){
    function ProcessResponse() {
        // Do something with 'response'
    }
    document.readyState == 'complete' ? ProcessResponse() : $(ProcessResponse);
}
Ganesh Jadhav
  • 2,830
  • 1
  • 20
  • 32
  • @Ramesh: Your doubt is absolutely right. See I have updated the answer. – Ganesh Jadhav Dec 12 '13 at 09:50
  • Does this code contain a race condition, or are JavaScript methods never interrupted / pre-empted? – Zack May 11 '15 at 21:45
  • @Zack By what I understand about a race condition, this is not one. Since the main event takes place only after both the required events have taken place. And I don't think javascript methods are interrupted ever. – Ganesh Jadhav May 12 '15 at 14:30
0

I recently read Learning jQuery Deferreds and I believe this is the elegant solution I was looking for, a couple of months ago, when I posted this question!

To use it, I create a global Deferred object, which is resolve()-ed when the DOM is ready. From that Deferred object, I extract a promise, and the $.ajax() call returns a promise. I don't want onReply() (or the ajax error handling) called until both those actions have completed, or in Deferred jargon, until both the promises have been resolved. The way we do that is using $.when(), which takes a list of promises(*) to wait for, and returns another promise object, to which we can attach the fail() and done() handlers.

*: Technically they do not need to be promise objects; they can be normal functions too.

Here is a first draft of that solution:

var someGlobal = 'whatever';
var readyToInit = $.Deferred();
...
function onReply(response){
  //Do something
}
...
var ajaxPromise = $.ajax({
   'url':'call_me.json',
   'type':'POST',
   'data':{x:someGlobal,y:'Dude!'}
  });

$.when( ajaxPromise, readyToInit.promise() )
  .fail(function(jqXHR,status){
    console.log('AJAX ERROR:' + status);
    })
  .done(onReply);
...
$(function() {  //OnReady
    readyToInit.resolve();  //Anything waiting for the page to load can go now
});
Darren Cook
  • 27,837
  • 13
  • 117
  • 217