25

Right after my script is loaded I am making an Ajax request to get some translations. This should always return after the document is ready since I am loading my scripts at the bottom of the page, but I am still curious if it would be possible to get a Deferred Object on the document ready state.

That way it would be possible to make sure that both, the document is ready and the Ajax call returned successfully before doing anything else, e.g. like this:

$.when( $.ajax('translations'), document.ready())
.then(function(){
    // Start doing stuff here
});
lonesomeday
  • 233,373
  • 50
  • 316
  • 318
Daff
  • 43,734
  • 9
  • 106
  • 120

6 Answers6

24

You can associate a deferred object with the document using data(), and resolve() it in your ready handler. This way, you should be able to use the stored deferred object with $.when():

$(document).data("readyDeferred", $.Deferred()).ready(function() {
    $(document).data("readyDeferred").resolve();
});

$.when($.ajax("translations"), $(document).data("readyDeferred"))
 .then(function() {
    // Start doing stuff here.
});
Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • Thanks, simple and straightforward. That will probably also work with a global variable or something similar. – Daff May 30 '11 at 15:24
  • 1
    @Daff, absolutely. I personally prefer using `data()` instead of a global variable because it's more flexible and avoids polluting the global namespace. – Frédéric Hamidi May 30 '11 at 15:34
  • 8
    Pedantic note. There's no reason to store the variable at all. You only need it during setup phase, so use closure scope: `(function() { var deferred = new $.Deferred(); $(function() { deferred.resolve(); }); $.when($.ajax('foo'), deferred).then(function() {}); })();`... If you use local scopes, there's no need to store, just let the closures bind it for you... – ircmaxell Mar 26 '12 at 14:16
21

Here's a cleaned up version of ircmaxell's comment:

(function() {
  var doc_ready = $.Deferred();
  $(doc_ready.resolve);
  $.when(doc_ready, $.ajax('translations')).then(function() {
    console.log("done");
  });
})();

edit

Some clarification to stop the incorrect edits:

Passing a function to the jquery object (e.g. $(some_func)) is the same as $(document).ready(some_func).

Therefore, the $(doc_ready.resolve); line is just shorthand for something like this:

$(document).ready(function() {
  doc_ready.resolve()
});
Pascal Venot
  • 215
  • 2
  • 6
zaius
  • 6,409
  • 4
  • 28
  • 50
9

Try this:

$.when($.ajax('translations'), $.ready).then(function() {
    // Start doing stuff here
});
Eric
  • 95,302
  • 53
  • 242
  • 374
thorn0
  • 9,362
  • 3
  • 68
  • 96
  • 3
    Note that `$.ready` is not in fact a deferred, but happens to have a `promise` method anyway. – Eric Oct 30 '13 at 20:18
  • 1
    No, it's not yet been documented: https://github.com/jquery/api.jquery.com/issues/205 – thorn0 Nov 02 '13 at 11:57
6

My version is:

$.when(
  $.Deferred(function() { $(this.resolve); }), 
  $.ajax('translations')).
  then(function() { console.log("done"); });
  • 1
    I like the way the deferred is contained. One suggestion would be to change to order of your deferreds, so that your callback function first argument would be any value that was resolved for the $.ajax deferred. – Asaf Jun 02 '13 at 14:25
2

Update for reference (2015):

This is available in current versions of jQuery:

$.when($.ready).then(...);

It is also simple to convert to a stream using highlandjs:

_($.when($.ready)).map(transform).pipe(output) // etc.
Stuart Wakefield
  • 6,294
  • 24
  • 35
0

jQuery's when is not a proper promise. You can force it into one like this:

function documentReady() {
    return Promise.resolve($.when($.ready));
}

Usage:

documentReady().then(function($) { ... });

It happens to resolve with $ so that's kind of convenient too.

Alternative implementation:

function documentReady() {
    return new Promise(r => $(r));
}
mpen
  • 272,448
  • 266
  • 850
  • 1,236