105

I am using RequireJS and need to initialize something on DOM ready. Now, RequireJS provides the domReady plugin, but we already have jQuery's $(document).ready(), which is available to me since I have required jQuery.

So I have got two options:

  1. Use the domReady plugin:

    require(['domReady'], function (domReady) {
        domReady(function () {
            // Do my stuff here...
        });
    });
    
  2. Use $(document).ready():

    $(document).ready(function() {
        // Do my stuff here...
    });
    

Which one should I choose, and why?

Both the options seems to work as expected. I am not confident in the jQuery's one because RequireJS is doing its magic; that is, since RequireJS will dynamically add scripts, I'm worried that DOM ready may occur before all of the dynamically-requested scripts are loaded. Whereas, RequireJS will add a burden on additional JS just for domReady when I already have jQuery required.

Questions

  • Why does RequireJS provide a domReady plugin when we can have jQuery's $(document).ready();? I don't see any advantage of including another dependency.
  • If its just to feed a need, then why not provide one for cross-browser AJAX?

As far as I know, a module that requires domReady won't be fetched or executed after the document is ready, and you could do the same requiring jQuery as well:

require(['jQuery'], function ($) {
    $(document).ready(function () {
        // Do my stuff here...
    });
});

To be more clear on my question: what's the difference between requiring domReady or jQuery?

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
Yugal Jindle
  • 44,057
  • 43
  • 129
  • 197
  • 4
    `I am not confident in jquery's dom ready` i want to mark it as offensive `:p` – Dakait Mar 11 '13 at 06:43
  • 3
    jQuery's dom ready is perfectly reliable, even on IE. Millions of people use it every day without knowing ;-) – John Dvorak Mar 11 '13 at 06:44
  • 1
    Are you in control of where your `script` tags go, or are you writing a library/plug-in that other people will use (and so they're in control of the location of the `script` tags in the markup)? – T.J. Crowder Mar 11 '13 at 06:49
  • Basically domContentLoaded is the key here. you can hook it up using javascript. http://ablogaboutcode.com/2011/06/14/how-javascript-loading-works-domcontentloaded-and-onload/. i am wondered why you don't have confident in Jquery ? jquery does the same via accessing domContentLoaded – Ravi Gadag Mar 11 '13 at 06:51
  • 3
    Oh god.. read it with the full context. `I am not confident in jquery's dom ready because requirejs is doing its magic.` Since, require is encapsulating jquery in limited local scope. That is not the point. (as far as the question is concerned). – Yugal Jindle Mar 11 '13 at 06:56

5 Answers5

95

It seems like all the key points were already hit, but a few details fell through the cracks. Mainly:

domReady

It is both a plugin and a module. If you include it in the the requirements array w/ a trailing ! your module won't execute until it's "safe" to interact w/ the DOM:

define(['domReady!'], function () {
    console.info('The DOM is ready before I happen');
});

Note that loading and executing are different; you want all your files to load as soon as possible, it's the execution of the contents that is time sensitive.

If you omit the !, then it's just a normal module that happens to be a function, which can take a callback that won't execute before the DOM is safe to interact with:

define(['domReady'], function (domReady) {
    domReady(function () {
        console.info('The DOM is ready before I happen');
    });
    console.info('The DOM might not be ready before I happen');        
});

Advantage when using domReady as a plugin

Code that depends on a module that in turn depends on domReady! has a very significant advantage: It does not need to wait for the DOM to be ready!

Say that we have a block of code, A, that depends on a module, B, that depends on domReady!. Module B will not finish loading before the DOM is ready. In turn, A will not run before B has loaded.

If you were to use domReady as a regular module in B, it would also be necessary for A to depend on domReady, as well as wrapping its code inside a domReady() function call.

Furthermore, this means that domReady! enjoys that same advantage over $(document).ready().

Re the differences between domReady and $(document).ready()

Both sniff out whether/when the DOM is ready in essentially the same way.

Re fear of jQuery firing at the wrong time

jQuery will fire any ready callback even if the DOM loads before jQuery does (your code shouldn't care which happens first.).

Arne Evertsson
  • 19,693
  • 20
  • 69
  • 84
fncomp
  • 6,040
  • 3
  • 33
  • 42
  • 2
    Beautiful, this is what I was looking for. Reasonable, well supported. – Yugal Jindle Mar 20 '13 at 06:20
  • @YugalJindle Is something missing for the bounty? :) – fncomp Mar 20 '13 at 07:03
  • I was just testing out what you wrote - here you go ! – Yugal Jindle Mar 20 '13 at 07:33
  • Looking at the domReady plugin code (https://github.com/requirejs/domReady/blob/master/domReady.js) I don't see any reason why you need to load it as 'domReady!' instead of 'domReady' - could you point me to the bit of code that causes that change in behaviour? – Jez Jan 19 '15 at 09:45
  • Look at the [public API exposure](https://github.com/requirejs/domReady/blob/2.0.1/domReady.js#L97). Defining the load method makes the `!` trigger a wait for domReady before the require callback is called. – fncomp Jan 20 '15 at 19:03
  • When I use the exclamation point, (e.g. http://dpaste.com/182FH3B), I get the error: `Uncaught TypeError: domReady is not a function` – nnyby Apr 27 '15 at 15:41
  • That links points to a partial paste. You shouldn't use the return value of the domReady plugin. The `domReady` plugin holds the resolution of your module until at least `DOMContentLoaded` there's nothing else useful for it to do. – fncomp Apr 27 '15 at 23:48
20

An attempt at answering your main question:

Why does requirejs provides a domReady plugin when we can have jquery's $(document).ready();?

They do two different things, really. RequireJS' domReady dependency signifies that this module requires the DOM to be completely loaded before it can be run (and can therefore be found in any number of modules in your application if you so desire), while $(document).ready() instead fires off its callback functions when the DOM is done loading.

The difference may seem subtle, but think of this: I have a module that needs to be coupled to the DOM in some way, so I can either depend on domReady and couple it at module definition time, or put down a $(document).ready() at the end of it with a callback to an init function for the module. I'd call the first approach cleaner.

Meanwhile, if I have an event that needs to happen right as the DOM is ready, the $(document).ready() event would be the go-to, since that does not in particular depend on RequireJS being done loading modules, provided the dependencies of the code you're calling it from are met.

It's also worth considering that you do not necessarily use RequireJS with jQuery. Any library module that needs DOM access (but does not rely on jQuery) would then still be useful by using domReady.

Gert Sønderby
  • 713
  • 7
  • 16
  • `domReady` is not a dependency for requirejs. It would be a dependency for the code if you are using `domReady` for DocumentReady event. Plus you seem to be confusing. – Yugal Jindle Mar 12 '13 at 16:53
  • 1
    Great answer, and an important hint to the subtleties many developers often do not realize (including myself ;-)). – Golo Roden Mar 13 '13 at 07:24
  • 1
    Yugal, I was referring to `domReady` as a dependency, because that's how it's used. Not as a dependency of RequireJS, but of the module where it is used. Maybe I should make that clearer in my text, do you have suggestions for how? – Gert Sønderby Mar 13 '13 at 10:20
  • Please see the *Update2* on the question. May be we are not on the same page. – Yugal Jindle Mar 14 '13 at 06:39
  • Yugal, what if you use MooTools? Qooxdoo? Anything not jQuery? RequireJS is not married to jQuery, although they do admittedly work really well together. – Gert Sønderby Mar 14 '13 at 08:21
  • True, in that case it means its equal to `$(document).ready()`. Then, I also added in `Update` that `If its just to feed a need, then why not provide one for Cross Browser ajax ?` – Yugal Jindle Mar 14 '13 at 10:27
  • As per `Update2` your answer seems contradicting. `Requirejs` does nothing new for `domReady`. – Yugal Jindle Mar 14 '13 at 10:28
  • Okay, I have no idea what you mean by the 'feed a need' comment. I guess I can't help you answer this question. Do be careful that you're not just looking for a bash on a particular bit of code that you dislike, though. What is stupid and useless to you may save another's project. – Gert Sønderby Mar 15 '13 at 11:02
  • No problem. I will get back if I find a reasonable explanation. Thanks – Yugal Jindle Mar 17 '13 at 17:12
6

Answering your bullets in order of appearance:

  • They both do accomplish the same thing
  • If you have reservations about jquery for whatever reason then use domReady
  • Correct, so just use jQuery
  • Because not everyone uses jQuery
  • I agree, just use jQuery
  • Plugins by definition 'feed a need'.
  • Cross Browser ajax isn't a thing. Cross Domain? There probably is, and if there isn't then there is no need to feed.
  • , -, -, - Ok

When it comes down to it, you are overthinking this. It's a mechanism to execute javascript on domReady. If you didn't have jQuery I would advocate the domReady plugin. Since you have jQuery then don't load more scripts to do something that is already available.

Clarity Update

The domReady plugin collects functions to call when the document is 'ready'. If it is already loaded then they execute immediately.

JQuery collects functions and binds a deferred object to the dom being 'ready'. When the dom is ready the deferred object will be resolved and the functions will fire. If the dom is already 'ready' then the deferred will already be resolved so the function will execute immediately.

This means that effectively they do exactly the same thing.

awbergs
  • 942
  • 4
  • 15
0

After some experimenting with requirejs with multiple modules I suggest using domReady.

I noticed that function associated with $(document).ready(...) is not called when multiple modules are loaded by requirejs. I suspect that dom is getting ready before all requirejs code is executed and jquery ready callback handler is called before it gets bound with user defined function i.e. within main module code.

require(['jquery',
    'underscore',
    'text!some_template.html',
    './my_module_1',
    './my_module_2',
    'domReady',
    'other_dependency_1',
    'other_dependency_2'
    ], function($, _, someTemplate, myModule1, myModule2, domReady) {

    $(document).ready(function() {
        console.info('This might never be executed.'); 
        console.info('Dom might get ready before requirejs would load modules.');
    });

    domReady(function () {
        console.info('This runs when the dom gets ready and modules are loaded.');
    });
});
  • 1
    I doubt that, If you have all the modules in your dependency list then all will be fetched and get into memory. post that jquery collects dom.ready instances before execution. – Yugal Jindle Jul 23 '13 at 12:51
  • If the DOM is already ready, the callback for `$(document).ready` will run immediately. – Danyal Aytekin Dec 17 '14 at 13:37
-1

I found I do this as part of the main entry so that all of my javascript is guaranteed that the DOM is ready and jquery is loaded. Not sure how great this is so welcome any feedback but here's my main.js:

require(['domReady!'], function(domReady){
    console.log('dom is ready');
    require(['jquery', 'bootstrap'], function(){
        console.log('jquery loaded');
        require(['app'], function(app){
            console.log('app loaded');
        });
    });
});
Bil Simser
  • 1,713
  • 1
  • 19
  • 27