3

As I understand:

  • $(document).ready() is fired when the entire html is parsed
  • scripts (inline or external) are parse-tree blocking

But to my surprise the following works unexpectedly:

<html>
<head>
</head>
<body>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <h1>This should show !</h1>
    <script>
            $(document).ready(function() {
                // Intentional infinite loop
                for(var i=0; i<100; i++) {
                    i--;
                }
            });
    </script>
    <h1>This should *not* show !</h1>
</body>
</html>

On executing the above, it runs into infinite loop and with a blank screen.

Expected to see This should show ! on the screen before running into the infinite loop.

Update

  • I have created a jsfiddle http://jsfiddle.net/csgu8/ [ Infinite loop might hang your tab ]
  • Please This is not a duplicate question

Update2

  • Please provide citation
  • AFAIK HTML can be partially rendered and rendering blocks only on css which is not used here (Comments ?)

Update3

  • In other words, JS is blocked in loop but what's blocking the rendering of partial DOM (already parsed) ?
  • HTML renders incrementally, why not in this case?

What's going on ??

Yugal Jindle
  • 44,057
  • 43
  • 129
  • 197

4 Answers4

0

If you read the jQuery documentation for ready, you should take note of the line In most cases, the script can be run as soon as the DOM hierarchy has been fully constructed. My takeaway from this line is that this does not necessarily mean the page will display. So even though you do not have any css code, that doesn't mean your document will display.

Here is a link to a StackOverflow question that does a good job explaining this: window.onload vs $(document).ready()

Here is a link to a page that describes the entire page rendering process: http://friendlybit.com/css/rendering-a-web-page-step-by-step/

If you take note of step 18 in the above link, after all the HTML & CSS is loaded, and after the Javascript is executed, then the page is actually printed. The following StackOverflow question contains good links to further illustrate this point: Describe the page rendering process in a browser?

Further clarification (in response to update 3):

Here's my summary for the friendlybit article:

  1. First you build up the HTML code itself. In this case, it would be your header elements.
  2. Then CSS is parsed.
  3. Then, because you called document.ready(), the Javascript is executed inside.
  4. In the case that your Javascript completes, then you finally have everything set-up all nicely, and you can proceed to actually render the page (another way to look at it is "paint" the page).

Here is a JSFiddle that shows this at work (you will need to open up console to see it work): http://jsfiddle.net/aLbmB/

The JSFiddle shows you that the two header elements are parsed before the Javascript is executed. If you change the code in the for-loop to the following:

$("#header2").text($("#header2).text() + "----");
i--;

You will see that the text never renders, which hopefully goes to show that the Javascript is being executed, and as a result, you never actually get to the page rendering part. Another good example is when you are pulling data from a database via jQuery and are waiting for it to all load in. The larger the data set, the longer it takes for the page to load (even though the HTML code is already there).

The way I think about this logically is that you first get all your values set-up nicely before you execute any Javascript on them. Then you execute the Javascript, and once all that is set in stone, you then allow your user to view your finished product. Of course, this is not the case when you don't use document.ready(), but I guess the tradeoff there is speed vs. predictability (in execution).

Extra Note (courtesy of lazertyuiopl):

A good point was made that "you can trigger a paint of already parsed elements using alert()". If this is done, then it will appear as if each element is being painted one at a time, top to bottom. I would recommend checking this JSFiddle out: http://jsfiddle.net/K9kG8/7/

Run it again after it's loaded and you'll see what I believe Yugal Jindle expects.

Added aside: I think this question isn't a duplicate, but more of a question clarifiable through another question's answer. In other words, a specific example.

Community
  • 1
  • 1
Zhouster
  • 746
  • 3
  • 13
  • 23
  • Now you get it. What's keeping the first h1 from rendering – Yugal Jindle Jul 16 '14 at 04:46
  • Please see **Update3** – Yugal Jindle Jul 16 '14 at 05:32
  • You might want to add that you can trigger a paint of already parsed elements using alert(). This [jsfiddle](http://jsfiddle.net/K9kG8/4/) should explain everything nicely if run with chrome timeline tool. I think the browser waits that scripts are done before painting to allow dynamic javascript styling on page load, but I could not find proof for this... – IazertyuiopI Jul 16 '14 at 08:01
  • @lazertyuiopl: Yeah, that JSFiddle is a pretty good point. I will say though that the for loop could be taken out (confused me for a second there). I'll definitely add that as an edit though. Thanks! – Zhouster Jul 16 '14 at 16:01
0

Here is what was happening: ( Thanks to @Zhouster for inspiration )

  • Yes, HTML is parsed partially and partial parse-tree is created
  • Yes, Javascript (inline or external) both are parse-tree blocking

Explanation of above code (In the question) - Mistake spotted:

<html>
<head>
</head>
<body>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <h1>This should show !</h1>               <!-- 1st h1 -->
    <script>
            $(document).ready(function() {    // Mistake: Will be executed later when parse-tree is complete
                // Infinite loop
                for(var i=0; i<100; i++) {
                    i--;
                    console.log($("h1").text());  // Prints both 1st & 2nd h1 in console
                }
            });
    </script>
    <h1>This should *not* show !</h1>        <!-- 2nd h1 -->
</body>
</html>
  • $(document).ready(function() { ... }); wraps the callback function which will by definition of document ready will be executed when the parse-tree is complete.
  • So, the loop is wrapped in the callback and it waits for the document to complete parse-tree
  • Once the parse-tree is completed, the loop kicks in and we can see console logs for 1st h1 and 2nd h1
  • We are unable to see the h1 on the screen because out of some reason it blocks paint
  • Since, we used document ready both h1 are part of parse-tree and we can see console logs for both h1 (But paint gets blocked out of some reason so blanks screen)

Little Variation - To highlight the concept:

<html>
<head>
</head>
<body>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <h1>This should show !</h1>               <!-- 1st h1 -->
    <script>
                // **** Without document ready ****
                // Not an infinite loop
                for(var i=0; i<100; i++) {
                    console.log($("h1").text());  // Prints only 1st h1
                }

               // **** Document ready ****
               $(document).ready(function() {
                  // Not an infinite loop
                   for(var i=0; i<100; i++) {
                       console.log($("h1").text());  // Prints both 1st & 2nd h1 in console
                   }
               });
    </script>
    <h1>This should *not* show !</h1>        <!-- 2nd h1 -->
</body>
</html>
  • Since, there is no document ready in the first loop so the loop will not wait for the parse-tree
  • Loop kicks in when we just had 1st h1 in our partial parse-tree, parse-tree is blocked until the script completes
  • This will print only 1st h1 on the console since its unaware of the 2nd h1
  • Once the first loop is complete, second loop is again wrapped in document ready so, it will be stored as a callback and the script will complete and unblock the parse tree
  • parse-tree will see 2nd h1 and the parse-tree will be complete
  • Now, once the parse-tree is complete document ready is fired and the callback executes
  • This time (2nd loop), will see both the h1 and will print the contents of both to the console
  • So, our concept that js blocks parse-tree holds correct
  • Since the loops are not infinite this time, so paint will be fired and we can see both the h1 on the screen

Mystery resolved :)

Yugal Jindle
  • 44,057
  • 43
  • 129
  • 197
-1

Your concept is wrong.

html will be rendered and the script won't block rendering the html. But the ready handler script only called after the document is ready.

Bhojendra Rauniyar
  • 83,432
  • 35
  • 168
  • 231
  • 2
    @lazertyuiopl: the effort someone puts in to answer a question should not be downvoted. if the question is a duplicate downvote the question and not the answer. And downvote the answer if it is incorrect or not related to the question. – A J Jul 15 '14 at 08:10
  • Please see jsfiddle and the question is not duplicate. – Yugal Jindle Jul 15 '14 at 10:10
  • 1
    @IazertyuiopI: While it might be a bad practise ("rep who\re") to answer obvious dupe question, I fail to see what this is an exact duplicate of. Instead of downvoting answer, please [vote to close](https://stackoverflow.com/help/privileges/close-questions) or (if you don't have the rep for that) comment on the question with a phrase like "*[possible|exact] duplicate of (link)*". I'd immediately close it if you can suggest a proper one. – Bergi Jul 15 '14 at 15:53
  • 1
    Well, it seems to me that the answer to the op's concerns can be found [here](http://stackoverflow.com/questions/1307929/javascript-dom-load-events-execution-sequence-and-document-ready?rq=1), [here](http://stackoverflow.com/questions/2683072/jquery-events-load-ready-unload?rq=1), [here](http://stackoverflow.com/questions/9657572/jquery-document-ready). However I have to agree with @Zhouster that the question is not an exact duplicate, its more that the answer can be found by looking at similar questions.. – IazertyuiopI Jul 16 '14 at 04:34
  • @lazertyuiopl: My hope is that in sufficiently answering this question, we help others better understand the nuance here. As a result, maybe we'll move towards that magic number of similar questions where no new similar ones pop up. Who knows. – Zhouster Jul 16 '14 at 07:30
-1

That's the difference between Document ready and window.load

The DOM structure is ready and can be queried. A better test would be run a jQuery selector and confirm that all elements on the page are accessible. It doesn't necessarily mean the elements are rendered.

This is because, most browsers, keep elements hidden until CSS is parsed.

Naman Goel
  • 1,525
  • 11
  • 16
  • Please see `jsfiddle` and the question is not duplicate. – Yugal Jindle Jul 15 '14 at 10:09
  • @Zhouster Please answer separately if you have figured it out. Please provide citation for the same, AFAIK HTML can be partially rendered and rendering blocks only on `css` which is not used here. – Yugal Jindle Jul 15 '14 at 17:56