7

Please, see code:

<!-- ... -->
<head>
    <style type="text/css"> body { background: gray; } </style>
</head>
<body>
    <p>
        Firefox does not even shows blank page.
        Tab is stuck in "suggested sites" for 5 seconds.
    </p>
    <p>
        Chrome show just blank white. No text, no background. For 5 seconds.
    </p>
    <p>
        DOMContentLoaded event handler blocks page
        loading and rendering. Browser does not start
        rendering page until DOMContentLoaded
        handler function return.
    </p>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            var timestamp = Date.now() + 5000; while (Date.now() < timestamp);
            // or synchronous 5 seconds XHR as an equivalent of loop
        });
    </script>
</body>
<!-- ... -->

Static html+css is more than sufficient to render content (though without IMGs, and but good layout's blocks does not depend on imgs sizes). General page layout should be shown immediately like it was always intended to. And only after rendering (or at least starting to draw it) Javsacript should run, no matter be it just controls click bindings or endless loop as in example here.

How can I run JS after static page layout is actually rendered, or at least started to appear?

(and "ready" event is not suitable here, because it is not guaranteed to fire in any reasonable time)

  • As you see from example I am not using document write nor plan to.
  • I also place script right before body closing tag
  • I am not doing any actual work right in script tag - I subsribe to the event.

Why browser prevents (blocks) user from seeing statically defined content? Does at least modern browsers can stop that nonsense?

UPD. clarification

If you use DOMContentLoaded for regular seemingly harmless tasks (subsribing to buttons events, initialising async load of other code, etc.) you in fact DO delaying user from seeing contents and that IS the real problem with DOMContentLoaded. Loop blocking here is intentional in example, just to prove that it really blocks, for those who erroneously believes DOMContentLoaded is "async"/"non-blocking" safe thing (which is not).

  • 1
    [Why not use `setTimeout`?](http://jsfiddle.net/ods26xk1/1) It's not exactly clear what you're trying to achieve here. – André Dion Sep 18 '15 at 18:30
  • @AndréDion Yeah not entirely clear, but I gathered that the blocking was intentional -- he just wanted it to start after the main content is displayed. – wwwmarty Sep 18 '15 at 18:34
  • maybe the while() is a stub for a synchronous ajax call... – wwwmarty Sep 18 '15 at 18:35
  • André, "load" is not an option, it fires after "dependent resources" (page images, iframes etc.) be downloaded, which in some cases is tens of seconds or even more. –  Sep 18 '15 at 18:42

1 Answers1

3

Interesting and unexpected. I solved it with requestAnimationFrame(callback), like so:

function foo() {
    window.requestAnimationFrame(function() {
        window.requestAnimationFrame(function() {
            var timestamp = Date.now() + 5000; while (Date.now() < timestamp){};
            alert('now');
        });
    });
}
document.addEventListener('DOMContentLoaded', foo);
wwwmarty
  • 858
  • 4
  • 10
  • Brilliant finding, thank you. That exactly how I expected it work. This is strange, that there is no other convenient and standard way for such fundamental thing and the problem is ignored. –  Sep 18 '15 at 18:10
  • Ok that is very annoying. Chrome likes a second animationFrame, but not the first one. Updated answer.... and I'm terrified to try this in IE ;) – wwwmarty Sep 18 '15 at 18:21
  • 2
    Don't use rAF if you don't actually need to sync with the animation frames. Use setTimeout for generic timeout needs. – Xanthir Sep 18 '15 at 20:58