Is there any equivalent of "$ (document) .ready ()" with pure Javascript?

10

In jQuery, we need to use $(document).ready() to know if the document has been loaded and then safely run our jQuery script.

According to the jQuery documentation

  

A page can not be manipulated safely until the document is "ready." jQuery detects this state of readiness for you.

Translation:

  

The page can not be safely manipulated until the document is "done". jQuery detects this state of readiness for you.

Now, in the case of pure Javascript, without jQuery or any other framework, is there any way to detect that the document was loaded, to have the same assurance that we have with $(document).ready() ?

    
asked by anonymous 29.06.2016 / 21:31

3 answers

11

What the jQuery does is to read the document.readyState property when the page loads, and if it is not already loaded listen for one of the load or DOMContentLoad events. The first event to be called triggers ready .

In practice simplifying would be like this ( jsFiddle ):

function ready() {
    // quando esta função correr o DOM está acessível
}

function completed() {
    document.removeEventListener("DOMContentLoaded", completed);
    window.removeEventListener("load", completed);
    ready();
}

if (document.readyState === "complete" ||
    (document.readyState !== "loading" && !document.documentElement.doScroll)) {
    ready(); // está pronto!
} else { // ainda não está pronto...
    document.addEventListener("DOMContentLoaded", completed);
    window.addEventListener("load", completed);
}

IE 8 had a bug with the scroll and so this line refers to Scroll. There is a very good article about it ( link ), but since IE8 is no longer supported it can be removed.

The MooTools version is similar, a bit more complex and therefore more complete, and uses MooTools' internal event engine. It also takes into account older browsers that do not have readystatechange . But that does not matter anymore today.

For modern browsers can be done like this: link ):

var domReady = function(ready) {
    if (document.readyState != 'loading') return ready();
    document.addEventListener('DOMContentLoaded', ready);
    function _ready() {
        document.removeEventListener('DOMContentLoaded', ready);
        ready();
    }
}

For older browsers you could do this ( link ), keeping it simple:

var domReady = function(ready) {
    var attacher = document.addEventListener ? {
        add: 'addEventListener',
        remove: 'removeEventListener'
    } : {
        add: 'attachEvent',
        remove: 'detachEvent'
    };

    function completed() {
        document[attacher.remove]("DOMContentLoaded", completed);
        window[attacher.remove]("load", completed);
        ready();
    }

    if (document.readyState === "complete" ||
        (document.readyState !== "loading" && !document.documentElement.doScroll)) {
        ready(); // está pronto!
    } else { // ainda não está pronto...
        document[attacher.add]("DOMContentLoaded", completed);
        window[attacher.add]("load", completed);
    }
}
    
29.06.2016 / 21:36
6

To be similar to the jQuery operation we have to add an extra random check.

  • Note that interactive does not work well in IE so I used doScroll
  • Note that document.readyState is not supported by some browsers, so I kept onload as a "fallback"
  • To use document.readyState you need setInterval or setTimeout
  • The variable isReady is used to avoid running a script all the time already loaded (also avoiding problems in browsers without document.readyState support)
  • The (function () { serves to isolate the variable isReady getting within the scope
  • The DOMContentLoaded event fires when the initial HTML document has been fully loaded and parsed, without waiting for style sheets, images, and subframes to terminate loading, but is not supported by some older browsers such as IE8
  • In the script below, the DOMContentLoaded runs parallel to the other functions, ie those who finish first will fire the callback.
  • The event load in window is a guarantee that everything fails or is a browser with no support whatsoever (it's very rare)

The code looks like this:

(function (w, d) {
    var isReady = false;

    w.domReady = function(callback)
    {
        /*
        Se a página já estiver carregada e já tiver rodado alguma vez
        o window.domReay então esta if evita fazer registro de eventos
        ou testes desnecessários, assim otimizando o tempo de resposta
        */
        if (isReady) {
             callback();
             return;
        }

        var done = false;
    
        var doc = d.documentElement;
    
        var attacher = d.addEventListener ? {
            add: 'addEventListener',
            remove: 'removeEventListener'
        } : {
            add: 'attachEvent',
            remove: 'detachEvent'
        };
    
        function completed() {

            /*
            A variável done impede que o script seja executado duas vezes
            */
            if (done) { return; }

            done = true;
            isReady = true;
    
            d[attacher.remove]("DOMContentLoaded", completed);
            w[attacher.remove]("load", completed);
            callback();
        };
    
        if (d.readyState === "complete") {
            /*Se o navegador suportar readyState e a página já estiver carregada*/
            completed();
        } else if (doc.doScroll) {

            /*interactive para IE8 não funciona bem, doScroll é um fallback para IE8*/

            (function doScrollTest() {
                try {
                    doc.doScroll('left');
                    completed();
                } catch(e) {
                    setTimeout(doScrollTest, 50);
                }
            })();
        } else if (d.readyState) {

            /*Checa se é interactive ou completed*/

            (function readyStateTest() {
                if (d.readyState !== "loading") {
                    completed();
                } else {
                    setTimeout(readyStateTest, 50);
                }
            })();
        }
    
        d[attacher.add]("DOMContentLoaded", completed);
        w[attacher.add]("load", completed);
    };
})(window, document);

//Usando:
domReady(function() {
    console.log("ready");
});

domReady(function() {
    console.log("olá mundo");
});

domReady(function() {
    domReady(function() {
        console.log("domReady dentro de domReady");
    });
});

window.onload = function () {
    domReady(function() {
       console.log("domReady dentro de Onload");
    });
};
    
29.06.2016 / 22:59
3

You can also use the script tags at the end of the body, as shown in the code below. With the script inside the body the code will only be executed when the body is loaded.

<!DOCTYPE html>
<html lang="pt-br">
<head>
    <title></title>
</head>
<body>
    <script>
        alert('A página foi carregada!');
    </script>
</body>
</html>
    
29.06.2016 / 21:37