Pregunta Equivalente de JavaScript a $ .ready () de jQuery: cómo llamar a una función cuando la página / DOM está lista para ello [duplicar]


Esta pregunta ya tiene una respuesta aquí:

De acuerdo, esta podría ser una pregunta tonta, aunque estoy seguro de que hay muchas otras personas haciendo la misma pregunta de vez en cuando. Yo, solo quiero estar 100% seguro de cualquier manera. Con jQuery todos sabemos lo maravilloso

$('document').ready(function(){});

Sin embargo, supongamos que quiero ejecutar una función que esté escrita en JavaScript estándar sin una biblioteca que la respalde, y que deseo iniciar una función tan pronto como la página esté lista para manejarla. ¿Cuál es la forma correcta de abordar esto?

Sé que puedo hacer:

window.onload="myFunction()";

... o puedo usar el body etiqueta:

<body onload="myFunction()">

... o incluso puedo intentar al final de la página después de todo, pero al final body o html etiqueta como:

<script type="text/javascript">
   myFunction();
</script>

¿Qué es un método compatible con varios navegadores (viejo / nuevo) para emitir una o más funciones de forma similar a jQuery's $.ready()?


907
2018-03-27 23:57


origen


Respuestas:


Lo más simple que puede hacer en ausencia de un marco que haga toda la compatibilidad entre navegadores para usted es simplemente hacer una llamada a su código al final del cuerpo. Esto es más rápido de ejecutar que un onload controlador porque esto solo espera que el DOM esté listo, no que todas las imágenes se carguen. Y, esto funciona en todos los navegadores.

<html>
<head>
</head>
<body>
Your HTML here

<script>
// self executing function here
(function() {
   // your page initialization code here
   // the DOM will be available here

})();
</script>
</body>
</html>

Si realmente no quieres hacerlo de esta manera y necesitas compatibilidad de navegador cruzado y no quieres esperar window.onload, entonces probablemente deberías ver cómo un framework como jQuery implementa es $(document).ready() método. Es bastante complicado dependiendo de las capacidades del navegador.

Para darle una pequeña idea de lo que hace jQuery (que funcionará donde sea que se coloque la etiqueta del script).

Si es compatible, prueba el estándar:

document.addEventListener('DOMContentLoaded', fn, false);

con una reserva para:

window.addEventListener('load', fn, false )

o para versiones anteriores de IE, usa:

document.attachEvent("onreadystatechange", fn);

con una reserva para:

window.attachEvent("onload", fn);

Y, hay algunas soluciones alternativas en la ruta del código de IE que no acabo de seguir, pero parece que tiene algo que ver con los marcos.


Aquí hay un sustituto completo para jQuery's .ready() escrito en javascript simple:

(function(funcName, baseObj) {
    // The public function name defaults to window.docReady
    // but you can pass in your own object and own function name and those will be used
    // if you want to put them in a different namespace
    funcName = funcName || "docReady";
    baseObj = baseObj || window;
    var readyList = [];
    var readyFired = false;
    var readyEventHandlersInstalled = false;

    // call this when the document is ready
    // this function protects itself against being called more than once
    function ready() {
        if (!readyFired) {
            // this must be set to true before we start calling callbacks
            readyFired = true;
            for (var i = 0; i < readyList.length; i++) {
                // if a callback here happens to add new ready handlers,
                // the docReady() function will see that it already fired
                // and will schedule the callback to run right after
                // this event loop finishes so all handlers will still execute
                // in order and no new ones will be added to the readyList
                // while we are processing the list
                readyList[i].fn.call(window, readyList[i].ctx);
            }
            // allow any closures held by these functions to free
            readyList = [];
        }
    }

    function readyStateChange() {
        if ( document.readyState === "complete" ) {
            ready();
        }
    }

    // This is the one public interface
    // docReady(fn, context);
    // the context argument is optional - if present, it will be passed
    // as an argument to the callback
    baseObj[funcName] = function(callback, context) {
        if (typeof callback !== "function") {
            throw new TypeError("callback for docReady(fn) must be a function");
        }
        // if ready has already fired, then just schedule the callback
        // to fire asynchronously, but right away
        if (readyFired) {
            setTimeout(function() {callback(context);}, 1);
            return;
        } else {
            // add the function and context to the list
            readyList.push({fn: callback, ctx: context});
        }
        // if document already ready to go, schedule the ready function to run
        if (document.readyState === "complete") {
            setTimeout(ready, 1);
        } else if (!readyEventHandlersInstalled) {
            // otherwise if we don't have event handlers installed, install them
            if (document.addEventListener) {
                // first choice is DOMContentLoaded event
                document.addEventListener("DOMContentLoaded", ready, false);
                // backup is window load event
                window.addEventListener("load", ready, false);
            } else {
                // must be IE
                document.attachEvent("onreadystatechange", readyStateChange);
                window.attachEvent("onload", ready);
            }
            readyEventHandlersInstalled = true;
        }
    }
})("docReady", window);

La última versión del código se comparte públicamente en GitHub en https://github.com/jfriend00/docReady

Uso:

// pass a function reference
docReady(fn);

// use an anonymous function
docReady(function() {
    // code here
});

// pass a function reference and a context
// the context will be passed to the function as the first argument
docReady(fn, context);

// use an anonymous function with a context
docReady(function(context) {
    // code here that can use the context argument that was passed to docReady
}, ctx);

Esto ha sido probado en:

IE6 and up
Firefox 3.6 and up
Chrome 14 and up
Safari 5.1 and up
Opera 11.6 and up
Multiple iOS devices
Multiple Android devices

Implementación de trabajo y banco de pruebas: http://jsfiddle.net/jfriend00/YfD3C/


Aquí hay un resumen de cómo funciona:

  1. Crear un IIFE (expresión de función invocada inmediatamente) para que podamos tener variables de estado no públicas.
  2. Declarar una función pública docReady(fn, context)
  3. Cuando docReady(fn, context) se llama, comprueba si el controlador listo ya ha disparado. Si es así, solo programe la devolución de llamada recién agregada para disparar justo después de que este hilo de JS termine con setTimeout(fn, 1).
  4. Si el controlador listo no se ha disparado, agregue esta nueva devolución de llamada a la lista de devoluciones de llamadas para llamar más tarde.
  5. Verifique si el documento ya está listo. Si es así, ejecuta todos los manejadores listos.
  6. Si aún no hemos instalado detectores de eventos para saber cuándo está listo el documento, entonces instálelos ahora.
  7. Si document.addEventListener existe, luego instale manejadores de eventos usando .addEventListener() para ambos "DOMContentLoaded" y "load" eventos. La "carga" es un evento de respaldo por seguridad y no debería ser necesario.
  8. Si document.addEventListener no existe, luego instale manejadores de eventos usando .attachEvent() para "onreadystatechange" y "onload" eventos.
  9. En el onreadystatechange evento, verifique si el document.readyState === "complete" y si es así, llame a una función para disparar a todos los manejadores listos.
  10. En todos los demás manejadores de eventos, llame a una función para activar todos los manejadores listos.
  11. En la función para llamar a todos los manejadores listos, verifique una variable de estado para ver si ya hemos disparado. Si tenemos, no hagas nada. Si aún no hemos recibido una llamada, recorramos el conjunto de funciones listas y llamamos a cada una de ellas en el orden en que se agregaron. Establezca una bandera para indicar que todos han sido llamados para que nunca se ejecuten más de una vez.
  12. Borre la matriz de funciones para que se puedan liberar los cierres que puedan estar utilizando.

Manipuladores registrados con docReady() están garantizados para ser despedidos en el orden en que fueron registrados.

Si llamas docReady(fn) una vez que el documento ya está listo, la devolución de llamada se programará para ejecutarse tan pronto como el hilo de ejecución actual se complete utilizando setTimeout(fn, 1). Esto permite que el código de llamada asuma siempre que son devoluciones de llamada asíncronas que se llamarán más tarde, incluso si más tarde es tan pronto como termine el hilo actual de JS y se preserve el orden de las llamadas.


1350
2018-03-28 00:46



Me gustaría mencionar algunas de las formas posibles aquí junto con un truco de JavaScript puro que funciona en todos los navegadores:

// with jQuery 
$(document).ready(function(){ /* ... */ });

// shorter jQuery version 
$(function(){ /* ... */ });

// without jQuery (doesn't work in older IEs)
document.addEventListener('DOMContentLoaded', function(){ 
    // your code goes here
}, false);

// and here's the trick (works everywhere)
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
// use like
r(function(){
    alert('DOM Ready!');
});

El truco aquí, como lo explica el autor original, es que estamos comprobando document.readyState propiedad. Si contiene la cadena in (como en uninitialized y loading, los primeros dos Estados listos para DOM de 5) establecemos un tiempo de espera y comprobamos nuevamente. De lo contrario, ejecutamos la función aprobada.

Y aquí está el jsFiddle para el truco que funciona en todos los navegadores. 

Gracias a Tutorialzine por incluir esto en su libro.


99
2018-05-19 07:58



Si estás haciendo VAINILLA llanura JavaScript sin jQuery, entonces debe usar (Internet Explorer 9 o posterior):

document.addEventListener("DOMContentLoaded", function(event) {
    // Your code to run since DOM is loaded and ready
});

Arriba es el equivalente de jQuery .ready:

$(document).ready(function() {
    console.log("Ready!");
});

Que TAMBIÉN podría escribirse SHORTHAND así, que jQuery se ejecutará después de la lista incluso ocurre.

$(function() {
    console.log("ready!");
});

NO CONFUNDIRSE con ABAJO (que no está destinado a ser DOM listo):

NO use una IIFE como este que es autoejecutable:

 Example:

(function() {
   // Your page initialization code here  - WRONG
   // The DOM will be available here   - WRONG
})();

Este IIFE NO esperará a que se cargue tu DOM. (¡Incluso estoy hablando de la última versión del navegador Chrome!)


81
2017-07-01 20:31



Probado en IE9, y último Firefox y Chrome y también compatible con IE8.

document.onreadystatechange = function () {
  var state = document.readyState;
  if (state == 'interactive') {
      init();
  } else if (state == 'complete') {
      initOnCompleteLoad();
  }
}​;

Ejemplo: http://jsfiddle.net/electricvisions/Jacck/

ACTUALIZACIÓN - versión reutilizable

Acabo de desarrollar lo siguiente. Es un equivalente bastante simplista a jQuery o Dom ready sin compatibilidad hacia atrás. Probablemente necesite un mayor refinamiento. Probado en las últimas versiones de Chrome, Firefox e IE (10/11) y debería funcionar en navegadores más antiguos según lo comentado. Actualizaré si encuentro algún problema.

window.readyHandlers = [];
window.ready = function ready(handler) {
  window.readyHandlers.push(handler);
  handleState();
};

window.handleState = function handleState () {
  if (['interactive', 'complete'].indexOf(document.readyState) > -1) {
    while(window.readyHandlers.length > 0) {
      (window.readyHandlers.shift())();
    }
  }
};

document.onreadystatechange = window.handleState;

Uso:

ready(function () {
  // your code here
});

Está escrito para manejar la carga asíncrona de JS, pero es posible que desee sincronizar la carga de esta secuencia de comandos a menos que esté minimizando. Lo encontré útil en el desarrollo.

Los navegadores modernos también admiten la carga asíncrona de scripts que mejora aún más la experiencia. El soporte para async significa que se pueden descargar múltiples scripts de manera simultánea mientras se sigue procesando la página. Solo tenga cuidado cuando dependa de otros scripts cargados de forma asíncrona o use un minificador o algo similar a browserify para manejar dependencias.


71
2018-06-10 13:27



Las buenas personas de HubSpot tienen un recurso donde puedes encontrar metodologías de Javascript puro para lograr una gran cantidad de bondades de jQuery, incluyendo ready

http://youmightnotneedjquery.com/#ready

function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else if (document.addEventListener) {
    document.addEventListener('DOMContentLoaded', fn);
  } else {
    document.attachEvent('onreadystatechange', function() {
      if (document.readyState != 'loading')
        fn();
    });
  }
}

ejemplo de uso en línea:

ready(function() { alert('hello'); });

17
2018-03-28 00:46



Su método (colocando el script antes de la etiqueta de cierre del cuerpo)

<script>
   myFunction()
</script>
</body>
</html>

es una forma confiable de admitir navegadores antiguos y nuevos.


7
2017-11-24 05:15



Listo

function ready(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();}

Usa como

ready(function(){
    //some code
});

Para el código de invocación automática

(function(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();})(function(){

    //Some Code here
    //DOM is avaliable
    //var h1s = document.querySelector("h1");

});

Soporte: IE9 +


4
2018-06-19 06:03



No estoy muy seguro de lo que estás preguntando, pero tal vez esto pueda ayudar:

window.onload = function(){
    // Code. . .

}

O:

window.onload = main;

function main(){
    // Code. . .

}

3
2018-03-28 00:04



document.ondomcontentready=function(){} debería hacer el truco, pero no tiene compatibilidad completa con el navegador.

Parece que debes usar jQuery min


2
2017-10-28 17:52



Aquí hay una versión limpia y sin uso de evaluación de Ram-Swaroop's variedad "funciona en todos los navegadores": ¡funciona en todos los navegadores!

function onReady(yourMethod) {
  var readyStateCheckInterval = setInterval(function() {
    if (document && document.readyState === 'complete') { // Or 'interactive'
      clearInterval(readyStateCheckInterval);
      yourMethod();
    }
  }, 10);
}
// use like
onReady(function() { alert('hello'); } );

Sin embargo, espera 10 ms extra para ejecutarse, así que aquí hay una forma más complicada de hacerlo:

function onReady(yourMethod) {
  if (document.readyState === 'complete') { // Or also compare to 'interactive'
    setTimeout(yourMethod, 1); // Schedule to run immediately
  }
  else {
    readyStateCheckInterval = setInterval(function() {
      if (document.readyState === 'complete') { // Or also compare to 'interactive'
        clearInterval(readyStateCheckInterval);
        yourMethod();
      }
    }, 10);
  }
}

// Use like
onReady(function() { alert('hello'); } );

// Or
onReady(functionName);

Ver también ¿Cómo comprobar si DOM está listo sin un marco?.


2