Detect if a Document Has Loaded with JavaScript

By  on  

If you follow me on Twitter, you've probably noticed me whining about ChromeDriver.  For some reason it seems as though tests run before the document has properly loaded, leading to transient test failures and loads of frustration.

I thought the best way to avoid these problems was to ensure the document had loaded before each test run -- that way there's no excuse for transient loading problems.  Here's the snippet I use to check if the page is ready:

// The basic check
if(document.readyState === 'complete') {
    // good to go!
}

// Polling for the sake of my intern tests
var interval = setInterval(function() {
    if(document.readyState === 'complete') {
        clearInterval(interval);
        done();
    }    
}, 100);

I found it ironic that for years we went looking for the ultimate "domready" script and here I am in 2015 trying to figure out if the document has completed loading.  This is why we drink.

Recent Features

  • By
    Send Text Messages with PHP

    Kids these days, I tell ya.  All they care about is the technology.  The video games.  The bottled water.  Oh, and the texting, always the texting.  Back in my day, all we had was...OK, I had all of these things too.  But I still don't get...

  • By
    Chris Coyier’s Favorite CodePen Demos

    David asked me if I'd be up for a guest post picking out some of my favorite Pens from CodePen. A daunting task! There are so many! I managed to pick a few though that have blown me away over the past few months. If you...

Incredible Demos

  • By
    MooTools-Like Element Creation in jQuery

    I really dislike jQuery's element creation syntax. It's basically the same as typing out HTML but within a JavaScript string...ugly! Luckily Basil Goldman has created a jQuery plugin that allows you to create elements using MooTools-like syntax. Standard jQuery Element Creation Looks exactly like writing out...

  • By
    :valid, :invalid, and :required CSS Pseudo Classes

    Let's be honest, form validation with JavaScript can be a real bitch.  On a real basic level, however, it's not that bad.  HTML5 has jumped in to some extent, providing a few attributes to allow us to mark fields as required or only valid if matching...

Discussion

  1. Between DOMContentLoaded/load and document.readyState, I think that there are a few ensure that something is executed once the document is loaded.

    HTMLDocument.prototype.ready = function () {
    	return new Promise(function(resolve, reject) {
    		if (document.readyState === 'complete') {
    			resolve(document);
    		} else {
    			document.addEventListener('DOMContentLoaded', function() {
    			resolve(document);
    		});
    					}
    	});
    }
    document.ready().then(...);
    
    • Nice, Chris!

    • Thanks. I think you may have posted something very similar to this before. Or am I just imagining that?

  2. window.onload = function () { alert("keep it oldschool!") };
    
  3. I must be missing something obvious … why not just use jQuery?

    • You don’t use jQuery for a tiny code snippet…

    • DBJ

      Re use is cultural fenomenon Unless this is some kind of deep JavaScript master class? Which I think it is not.
      We have solved and debated this issue in 2008 last time.
      As I like to reuse what is shareable, I might point to this (instead of re writing it all over again).

    • DBJ

      No it was 2006 sorry … Very interesing page to read now.
      I suggest read it all, including comments, than come back here.

    • Vlad

      Personally, I will prefer js and only include jQuery if there is a strong need and justification for that. But that’s me, you might prefer to use jQuery, but i don’t think there is a need to get pissed for using js instead of jquery

  4. Kevin

    Alternately, I think you could use the ReadyStateChange Event.

    document.addEventListener('readystatechange', function docStateChange(e) {
        if(e.target.readystate === 'complete') {
            e.target.removeEventListener('readystatechange', docStateChange);
            done();
        }
    });
    
  5. A few people mentioning using an event listener. The problem is that I don’t know if the page is done loading; i.e. I can’t count on an event listener. Polling is the best way if I don’t know when my script is being injected.

    • Could you clarify this a litte? Using polling here seems a bit crude in comparison to replacing it with listening for a readystatechange event.

    • If my test is triggered after the page is ready (remember, I can’t count on when it starts), readystatechange will have already triggered and my signal will never be triggered.

    • Matijs

      But wouldn’t that be covered by your basic test already? So…only bind a listener in case the readyState isn’t complete yet?

    • Brian

      Maybe a combination of the two would suit

      if(document.readyState !== 'complete'){
           // use Kevin's addEventListener('readystatechange', ....
      }
      
  6. This is the version that I am using at the moment, I don’t know if it applies to your test though..

    // This is needed to prevent onreadystatechange being run twice
    var ready = false;
    
    document.onreadystatechange = function() {
    
    	if (ready) {
    		return;
    	}
    	
    	// interactive = DOMContentLoaded & complete = window.load
    	if (document.readyState == 'interactive' || document.readyState == 'complete') {
    		ready = true;
    		
    		// init you code here
    	}
    };
    
  7. peter

    How can i use this for a preloader?

    jQuery code is:

    $(window).load(function(){$('#preloader').fadeOut();});

    but i will use it without jQuery…

  8. thanks! worked perfectly for my case where no events seem to work as well. just wanted a script for console or bookmark which would keep scrolling down on infinite scrollers. it surely still can be improved, but this was good enough for me for now:

    window.scrollTo(0,document.body.scrollHeight)
    if (interval) {
        clearInterval(interval)
        interval = null
    } else var interval = setInterval(function() {
        console.log(document.readyState)
        if(document.readyState === 'complete') {
            window.scrollTo(0,document.body.scrollHeight)
    /*        setTimeout(function() {
                if(document.readyState === 'complete') clearInterval(interval)
            }, 100)*/
        }    
    }, 200)
    
  9. Jesse

    if (document.readyState === 'complete')

    Yep, that worked for me. Tough to find because there’s way more out there on the event ‘ready’ as opposed to the state ‘ready’.

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!