11

I found code in my codebase that has $(document).ready(function() {...} inside of another $(document).ready(function() {...}

e.g.

$(document).ready(function() {      

    // 20 lines... 

    $(document).ready(function() {
        foo()
    }

    // 200 lines...
}

function foo() {...}

I want to understand the order of execution so I can safely refactor out this nested callback. The outer callback seems to continue executing before the inner callback executes. Is the outer callback guaranteed to finish before the inner callback gets called?

David Groomes
  • 2,115
  • 19
  • 20
  • 7
    Post this mysterious code you speak of. – j08691 Mar 14 '14 at 20:12
  • 1
    Interesting, but why would you do this? – Jeffpowrs Mar 14 '14 at 20:14
  • Isn't this assigning a listener to the document's `ready` event *after* the event has fired? I would have expected that code (within the outer function) to never execute. – Michael Zalla Mar 14 '14 at 20:19
  • 1
    @MichaelZalla, I recently saw a case where code was (poorly) refactored from an IIFE into a `document.ready` callback and the original `document.ready` code was left as-is. Thankfully things kept working because that would have been a nightmare to debug. – zzzzBov Mar 14 '14 at 20:30

3 Answers3

14

Is the outer callback guaranteed to finish before the inner callback gets called?

Yes.

The way document.ready works is that it will wait for the readystatechange event to fire as being ready before the callback gets called, however it also runs setTimeout if the readystatechange event has already fired.

This means that code such as:

$(function () {
    a();
    $(b);
    c();
});

Where a, b, and c are all functions will execute in the order of:

  1. a
  2. c
  3. b

On a related note, people will question why you would want to run a document.ready call inside another document.ready call, and the short answer is that you wouldn't.

The only gain is that $(callback) is a bit more convenient to write than:

setTimeout(callback, 0);
zzzzBov
  • 157,699
  • 47
  • 307
  • 349
1

You should remove the inner $(document).ready and assign a name to that callback. Then call it as the last line the outer callback.

cainz
  • 79
  • 1
  • 6
-2

Yes. Event listeners are stored in a stack, and are just popped off one at a time when the event is triggered. This 'ready' listener just adds another 'ready' listener to the end of the stack. So when the first (outer) one is all done executing, the browser continues down the stack... until it gets to the second (inner) one, and then it executes that.

murdock
  • 123
  • 5
  • 3
    If the code were `document.addEventListener('readystatechange', callback, false)` this answer might be the case, however the way jQuery handles `document.ready` involves a lot of indirection and tricks to get things to work nicely cross-browser. It doesn't actually store subsequent ready callbacks in a stack once the first callback has executed. – zzzzBov Mar 14 '14 at 20:33