Matthew James Davis Matthew James Davis - 6 months ago 19
Javascript Question

Execute javascript after page load is complete

I have an html page with some pre-rendered content and some yet un-rendered content. I want to display the pre-rendered content immediately, and then begin rendering the rest of the content. I am not using jQuery.

See the following snippet. I have tried this various ways, including injecting my script before the closing body tag and providing my script to populate the DOM as a callback to

window.onload
,
document.body.onload
, and
document.addEventListener('DOMContentLoaded')
. In every case, the page does not display the pre-rendered content until the rest of the content is rendered.



<html><head></head>
<body>
<header>What it is, my doge?</header>
<div id="main"></div>
<script>
var main = document.getElementById('main');
for (var i = 0; i < 500; i++)
main.innerText += new Date();
</script>
</body>
</html>







<html><head></head>
<body>
<header>What it is, my doge?</header>
<div id="main"></div>
<script>
var main = document.getElementById('main');
document.body.onload = function() {
for (var i = 0; i < 500; i++)
main.innerText += new Date();
};
</script>
</body>
</html>







<html><head></head>
<body>
<header>What it is, my doge?</header>
<div id="main"></div>
<script>
var main = document.getElementById('main');
window.onload = function() {
for (var i = 0; i < 500; i++)
main.innerText += new Date();
};
</script>
</body>
</html>







<html><head></head>
<body>
<header>What it is, my doge?</header>
<div id="main"></div>
<script>
var main = document.getElementById('main');
document.addEventListener('DOMContentLoaded', function() {
for (var i = 0; i < 500; i++)
main.innerText += new Date();
});
</script>
</body>
</html>





One case that has worked is
window.setTimeout
with 0 timeout. However, this simply defers the function until there is nothing left to do. Is this the best practice, here?



<html><head></head>
<body>
<header>What it is, my doge?</header>
<div id="main"></div>
<script>
var main = document.getElementById('main');
window.setTimeout(function() {
for (var i = 0; i < 500; i++)
main.innerText += new Date();
}, 0);
</script>
</body>
</html>




Answer

In terms of a best practice, there isn't one. In terms of a good, common, and acceptable practices, there are a handful. You've hit one:

setTimeout(function() { }, 1);

In this case, the function is executed within the browser's minimum timeout period after all other in-line processing ends.

Similarly, if you want to ensure your function runs shortly after some condition is true, use an interval:

var readyCheck = setInterval(function() {
  if (readyCondition) {
    /* do stuff */
    clearInterval(readyCheck);
  }
}, 1);

I've been using a similar, but more generalized solution in my own work. I define a helper function in the header:

var upon = function(test, fn) {
    if (typeof(test) == 'function' && test()) {
        fn();
    } else if (typeof(test) == 'string' && window[test]) {
        fn();
    } else {
        setTimeout(function() { upon(test, fn); }, 50);
    }
}; // upon()

... and I trigger other functionality when dependencies are resolved:

upon(function() { return MyNS.Thingy; }, function() {
  //  stuff that depends on MyNS.Thingy
});

upon(function() { return document.readyState == 'complete';}, function() {
  // stuff that depends on a fully rendered document
});

Or, if you want a more authoritative good practice, follow Google's example. Create an external async script and inject it before your first header script:

var s = document.createElement('script'); s.type = 'text/javascript'; s.async = true;
s.src = '/path/to/script.js';
var header_scripts = document.getElementsByTagName('script')[0];
header_scripts.parentNode.insertBefore(s, header_scripts);

Google's solution theoretically works on all browsers (IE < 10?) to get an external script executing as soon as possible without interfering with document loading.

If you want an authoritative common practice, check the source for jQuery's onready solution.

Comments