5

The question is regarding the http://labjs.com – an awesome library for non-blocking JavaScript loading and dependencies managing.

I've read the docs, but I must be too tired or something – I couldn't find anything regarding DOM ready event. Are the scripts executed after the DOM's ready or not?

Perhaps if I do:

$LAB.script('my-library.js').wait(function(){ 
  // interacting with DOM 
});

Will it be safe? Or should I use some kind of $(function() {}) etc.?

Kyle Simpson
  • 15,725
  • 2
  • 33
  • 55
Misha Reyzlin
  • 13,736
  • 4
  • 54
  • 63
  • 1
    I just twittered this to the author ... I think I would be inclined to put my code in a jQuery "ready" handler or something equivalent. – Pointy Mar 23 '11 at 18:13

2 Answers2

7

Any script loader, by default, acts to unblock script loading from the page's DOM-ready and onload events, at least by intent/definition.

So, the straightforward answer is, NO, LABjs will not block script execution until DOM-ready. Some scripts loaded by LABjs may run before DOM-ready, while others may run after DOM-ready.

If you truly have cases where your code needs to wait for the DOM, you should use a framework like jQuery and use its built-in DOM-ready wrapper $(document).ready(...) to make that logic DOM-ready-safe.

However, there are many cases where people think they need to wait for DOM-ready, when they really don't:

  1. Most people conflate DOM-ready with "all scripts are done loading". If you are simply waiting for DOM-ready because you need to ensure that all your scripts have loaded, this is a mistaken and incorrect assumption to be making. Instead, use the facility of your script loader to determine when all scripts are loaded, and run them at the appropriate time, regardless of the DOM loading. With LABjs, this is as simple as having all your scripts in a single $LAB chain, and having a final .wait() at the end of the chain -- you can be assured that your code in that .wait() callback will not run until all the scripts have loaded and run.

  2. Most people think they need to wait for DOM-ready to do things like attaching event handlers, or firing off Ajax requests. This is also an incorrect assumption. If your code simply queries the DOM for elements to attach event handlers to, or if you are doing nothing with the DOM at all, but are instead making Ajax calls, don't wrap your logic in a DOM-ready wrapper.

  3. On the flip side, many people assume that if your code runs at the end of the body tag, then you don't need to wait for DOM-ready. Wrong. DOM-ready is DOM-ready, regardless where your code is specified.

In general, the only time your code really needs to be wrapped in a DOM-ready wrapper is if it is going to modify the DOM. Otherwise, don't wait for DOM-ready to run your code. Be smart about what is wrapped and what isn't.

Kyle Simpson
  • 15,725
  • 2
  • 33
  • 55
  • Thanks for a thoughtful answer, though in my case I really do need DOM interaction, in a sense that I create a shared (between different methods of a main object) collection of elements that is not in a ready state, when the script is). I am kind of not clear about you saying that one doesn't really need DOM to be ready to attach event handlers. How is it so? Thanks! – Misha Reyzlin Mar 23 '11 at 18:36
  • 1
    the only problem that DOM-ready waiting is really trying to solve is if your code is running before the browser knows what the DOM looks like. In older IE's for instance, if you try to modify an incomplete DOM, it causes a crash. For event handling, you are simply reading (not modifying) the DOM, so event attaching should be fine, assuming the element you want to attach to in fact exists. – Kyle Simpson Mar 23 '11 at 18:41
  • 1
    if you are using the preferable .delegate() or .live() patterns in jQuery for event attaching, then it's fine to attach an event handler even if the eventual target of that event doesn't yet exist (will be created from an Ajax call, for instance). Of course, if you call `$("#doesntexistyet").click(...)` then it will just silently fail. But, `$("#doesexist").delegate("#notyet",...)` will work just fine. – Kyle Simpson Mar 23 '11 at 18:49
  • @KyleSimpson This is not entirely true. For performance reasons You might want to postpone execution of JavaScript code until page is loaded. Users do not have to see 'Share it!' buttons right away, but they should see all essential images as soon as possible. Executing/downloading JavaScript code takes CPU and bandwidth needed for initial page load. – matt Nov 26 '13 at 11:24
  • @lucek what I said IS entirely true. the point you bring up about when code should execute (for performance reasons) is a separate/orthagonal issue. my discussion was purely about whether DOM-ready was needed to attach events without causing errors. on that angle, the information that I gave is entirely accurate. your point is additional information on a different angle. – Kyle Simpson Nov 26 '13 at 14:00
1

How about using jQuery's awesome Deferred object? This works like a charm:

var waitThenLaunch = function() {
    var deferredDocReady = $.Deferred();
    $(document).ready(function() {
        deferredDocReady.resolve();
    });
    var deferredScriptsReady = $.Deferred();

    // Load your last remaining scripts and launch!!!
    $LAB.script('last.js').wait(function(){ deferredScriptsReady.resolve(); });

    $.when(deferredDocReady, deferredScriptsReady).done(function() { launchApp(); });
};
$LAB.script('jquery.min.js')
    .script('another_script.js')
    .script('another_script.js').wait()
    .script('another_script.js')
    .script('another_script.js').wait(function(){ waitThenLaunch(); });

Find an excellent explanation here: http://www.erichynds.com/jquery/using-deferreds-in-jquery/

  • looks like an excellent idea to me, the only problem is that this prevents us from loading 91k with script loader (since jQuery has to be available in order to use $.Deferred in conjunction with $LAB), but it's an interesting approach! – Misha Reyzlin Dec 16 '11 at 16:49
  • 1
    actually the 91k is loaded with the script loader as well. the trick here is that the function waitThenLaunch is defined prior to script loading, but it's not interpreted until it's called, and only then jQuery needs to be available. the code also shows this. – Erik Schoel Dec 17 '11 at 14:31
  • I don't think you need deferred here (although they're cool). I think this simpler code will work just fine: https://gist.github.com/getify/9551ed8e42194f8dabef The trick is that `$(document).ready(..)` will fire your callback even if the document-ready event has already passed by the time you bind the event. It has that special behavior for usages exactly like this, where you're not sure if it's fired or not by the time you want to listen for it. – Kyle Simpson May 10 '13 at 14:24