why does underscore defer fix so many of my issues?

After using backbone for a couple of weeks I have realized that underscore defer ended up fixing many of the async issues I ran into regarding rendering various views. Can someone please help me understand exactly what underscore defer does and how is it different that $.ready() or other type of wait for dom to render functions. What are the down sides of using it ?

_.defer = function(func) {
    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
};

# These are equivalent
_.defer(fn);
setTimeout(fn, 1);

So defer is simply a one millisecond setTimeout. (It's got a few more convenience features but those aren't important here.)


JavaScript has run loops. It's single threaded, but its execution starts and stops based on events or timers. Each time your JS engine kicks on to run some code, it's starting one iteration of its run loop.

So what defer does is say "run this code in the next run loop".

_.defer(function() { alert('after'); });
alert('before');

This alerts "before" and then "after". This is because the the current run loop concludes which alerts "before", and then right afterward a new run loop starts and runs the code the alerts "after".

So anytime you have code right here, but you want it to run code which occurs after this code first, then you would use defer.

_.defer(functionToRunLast);
functionToRunFirst();

This can be handy with the DOM. Sometimes you change it, but the changes don't parse or render immediately. At the end of the run loop, the browser catches up and parses and renders the DOM, then the next run loop starts and can interact with the newly rendered DOM.

(Exactly what scenarios cause this delayed DOM parse, I'm not sure, but I've noticed it in my own projects in the past.)


It is NOT a replacement for DOM ready. The next run loop may happen before DOM ready ever fires, don't confuse these concepts.