Tuesday, March 4, 2014

window.ready vs window.load vs jQuery.ready() / DOMContentLoaded

DOMContentLoaded AKA jQuery.ready() is fired when the browser is done parsing the DOM, which includes script elements and iframes.

The load event is fired after DOMContentLoaded is fired. At this point, all resources are downloaded and ready which includes frames, images, etc. The browser's stop button stops spinning at this point.

index.html
<html>
    <head>
        <script type="text/javascript">
            console.log("HEAD_SCRIPT_INIT");
        </script>
    </head>
    <body>
        <script type="text/javascript">
            console.log("SCRIPT_TAG_1_INIT");
        </script>
        <script type="text/javascript">
            console.log("SCRIPT_TAG_2_INIT");
            document.addEventListener("DOMContentLoaded", function(){
                for(var i=0; i<10; i++)
                    console.log("SCRIPT_TAG_2_DOM_READY", i);
            });
            addEventListener("load", function(){
                console.log("SCRIPT2WINDOWLAOD");
            })
        </script>
        <iframe srcdoc='
            <script type="text/javascript">
                for(var i=0; i<10; i++)
                console.log("IFRAME_1_INIT:", i);
            </script>'>
        </iframe>
        <iframe srcdoc='
            <script type="text/javascript">
                for(var i=0; i<10; i++)
                    console.log("IFRAME_2_INIT:", i);
            </script>'>
        </iframe>
        <iframe src="iframe_3.html"></iframe>
        <iframe srcdoc='
            <script type="text/javascript">
                console.log("IFRAME_4_INIT");
                document.addEventListener("DOMContentLoaded", function(){
                    console.log("IFRAME_4_DOM_READY");
                })
                window.onload = function(){
                    console.log("IFRAME_4_WINDOW_ONLOAD");
                }
            </script>'>
        </iframe>
        <script async type="text/javascript" src="script_3.js"></script>
        <script type="text/javascript" src="script_4.js"></script>
        <script type="text/javascript">
            console.log("SCRIPT_TAG_5_INIT");
        </script>
        <script type="text/javascript">
            var script = document.createElement('script');
            script.innerText = 'console.log("HEAD_APPENDCHILD_INIT")';
            document.getElementsByTagName('head')[0].appendChild(script);
        </script>
        <script type="text/javascript">
            addEventListener("load", function(){
                console.log("SCRIPT7");
            })
        </script>
    </body>
</html>

iframe_3.html
<script type="text/javascript">
    console.log("IFRAME_3_INIT");
    document.addEventListener("DOMContentLoaded", function(){
        console.log("IFRAME_3_DOM_READY");
    })
    window.onload = function(){
        console.log("IFRAME_3_WINDOW_ONLOAD");
    }
</script>

script_3.js
console.log("SCRIPT_TAG_3_INIT");

script_4.js
console.log("SCRIPT_TAG_4_INIT");

Now, open index.html in a browser. Now open console and draw the following conclusions for yourself from our experiment.

As the downloaded html is parsed by the browser from top to bottom, any script tags in the head are executed followed by any script tags or iframe tags in the body.

Whether a script is specified inline or with an 'src' attribute, execution is done in order and it blocks parsing of the DOM unless the 'async' attribute is specified. 'async' scripts are downloaded out of order with respect to the other resources in the DOM. Downloading them will not block parsing the rest of the DOM, but they will block the load event during execution (it doesn't block DOMContentLoaded as far as I know).

Any script tags within iframe tags are parsed and executed right there if the content of the iframe is specified inline. If the iframe has an 'src' attribute, parsing of the DOM isn't blocked and the resource is downloaded in the background and executed when it's ready. Else it blocks further parsing. Also they fire their own DOMContentLoaded and load events and thus block the parents DOMContentLoaded and load events.

Iframes do not execute in parallel.

No script is EVER interrupted and execution is not switched to a different script just because an event was fired. The firing of every event blocks until the current block is done executing.

A script appended to head via JS code will be executed immediately (just like inline JS).

No comments:

Post a Comment