81

Estoy integrando una librería llamada chart.js en una página que estoy haciendo y he visto que en sus ejemplos utilizan la función window.onload en vez de $(document).ready() y me ha surgido la duda que da nombre a esta pregunta:

¿Cuál es la diferencia entre window.onload y $(document).ready()?

He encontrado una pregunta similar en SO en inglés llamada window.onload vs $(document).ready() pero no me ha quedado del todo claro, ya que mi inglés no es muy bueno.

Agradecería si alguien me puede resolver esta duda. Saludos

Joacer
  • 5,755
  • 9
  • 29
  • 54

5 Answers5

110

La diferencia la explica claramente jQuery en su documentación en inglés. Lamentablemente hay poca documentación de dicha biblioteca en castellano:

A page can't be manipulated safely until the document is "ready." jQuery detects this state of readiness for you. Code included inside $( document ).ready() will only run once the page Document Object Model (DOM) is ready for JavaScript code to execute. Code included inside $( window ).on( "load", function() { ... }) will run once the entire page (images or iframes), not just the DOM, is ready.


Una página puede ser manipulada sin riesgo de errores solamente cuando el documento está listo. jQuery se encarga de detectar dicho estado en nuestro lugar. El código incluido dentro de $( document ).ready() se ejecutará solamente cuando el Modelo de Objetos del Documento (DOM) esté listo para ejecutar código Javascript. Por su parte, el código incluido después de $( window ).on( "load", function() { ... }) se ejecutará solamente cuando la página entera (imágenes o iframes), no solamente el DOM, esté lista.

Fuente: jQuery learning center. -La traducción al castellano es propia.

Está claro, la diferencia viene indicada en el mismo nombre de cada método:

  • document: cuando esté listo sólo el documento, podríamos decir, la parte HTML.

  • window: cuando está lista toda la ventana, el documento y todo lo demás.


▸ window.onload()

El evento onload, cuya abreviatura es load se dispara al final del proceso de carga del documento. Es decir, cuando todos los objetos del DOM (imágenes, flash, scripts, frames) han terminado de cargarse. Una excepción son las hojas de estilo, que no siempre están cargadas al momento de lanzarse este evento.

▸ $(document).ready()

jQuery document.ready se ejecuta cuando todo el contenido HTML está listo, pero antes de las imágenes y otros recursos. En los navegadores modernos, es reemplazado por DOMContentLoaded.

Nota importante:

A partir de jQuery 3.0, $(document).ready() pasa al estado Deprecated, aunque seguirá funcionando, la misma desaparecerá del core de jQuery en la próxima versión de la librería (la versión 4).

La Guía de actualización de jQuery 3 (en inglés, esperando tener algún día esta documentación en castellano), explica lo siguiente al respecto:

Deprecated: document-ready handlers other than jQuery(function)

Due to historical compatibility issues there are a multitude of ways to set a document ready handler. All of the following are equivalent and call the function fn when the document is ready:

  1. $(fn);
  2. $().ready(fn);
  3. $(document).ready(fn);
  4. $("selector").ready(fn);

As of jQuery 3.0 the recommended way to add a ready handler is the first method, $(fn). As noted in the Event section, the $(document).on("ready", fn) event form has slightly different semantics and was removed in jQuery 3.0.


Debido a problemas históricos de compatibilidad existen varias formas de configurar el manejador de documentos. Todas las maneras siguientes (ver arriba) son equivalentes, y ejecutan la función fn cuando el documento está listo. A partir de jQuery 3.0 la forma recomendada de usar el manejador de documento listo es el primer método: $(fn); Como se indicó en la sección Evento, la forma $(document).on("ready", fn) tiene una semántica ligeramente diferente y se eliminó en jQuery 3.0.
Es decir, en cuanto empecemos a usar jQuery 3.0, lo mejor es dejar de usar nuestro tradicional $(document).ready(fn); y sustituirlo por $(fn);. También los métodos $().ready(fn); y $("selector").ready(fn);, hemos de sustituirlos simplemente por $(fn);, ya que jQuery 3 ha corregido los problemas de compatibilidad entre navegadores que obligaban a usar las 4 diferentes formas citadas más arriba para invocar una función llamada a hacer lo mismo.

Bastará sólo esto para verificar que el DOM está listo:

  $(function() 
  {
    console.log( "Ha ocurrido document.ready: documento listo" );
  });

Fuente: Guía de actualización de jQuery 3.

Nota: Existe un plugin para migrar nuestro código de librerías anteriores a jQuery 3, para más información, dejo aquí el enlace.


En resumen

Si vamos a trabajar con los elementos que componen la web (divs, inputs, …) usaremos $(document).ready(). Pero, si por el contrario, vamos a trabajar con imágenes para alinearlas o comprobar sus dimensiones tendremos que usar $(window).load().

Es un error muy extendido usar $(window).load() cuando vamos a trabajar solo con elementos del DOM, o usar $(document).ready() cuando vamos a trabajar con elementos que no estarán cargados al momento de ejecutarse dicha función.


Una imagen que ilustra los diferentes elementos de una ventana

introducir la descripción de la imagen aquí


Código de prueba

Veamos lo que ocurre en este fragmento de código en el cual se cargan por una parte los elementos del DOM y por otra parte un iframe de YouTube. Aunque sea mínima, verán la diferencia en el tiempo de carga en la consola.

Utilizaré la librería de jQuery 3 y $(function() {... en vez de $( document ).ready(function() {

Y de paso, si les gusta el flamenco no dejen de escuchar una de las canciones más bonitas de este género :)

<html>
<head>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script>
//        $( document ).ready(function() {
      $(function() {

        console.log( "Ha ocurrido document.ready: documento listo" );
    });
 
    $( window ).on( "load", function() {
        console.log( "Ha ocurrido window.load: ventana lista" );
    });
    </script>
</head>
<body>
    <p>Esto es un elemento p del DOM. Luego viene una ventana (iframe)</p>
    <iframe width="560" height="315" src="https://www.youtube.com/embed/NvVpAxQuBg4" frameborder="0" allowfullscreen></iframe>
</body>
</html>

 

 
BetaM
  • 30,571
  • 7
  • 32
  • 50
A. Cedano
  • 86,578
  • 19
  • 122
  • 221
  • 2
    Muchas gracias por tu aclaración, la librería que estoy utilizando trabaja sobre un div que dentro tiene un canvas para poder dibujar la gráfica. Por lo que has dicho en tu resumen debería de utilizar el $(document).ready() en vez del Window.onload() ya que voy a trabajar con los elementos del DOM. – Joacer Feb 28 '17 at 09:19
  • 1
    @Joacer Es correcto. Si fueses a trabajar con un iframe, una imagen, flash u otro que no se cargue en el DOM deberías usar window.load() – A. Cedano Feb 28 '17 at 09:50
16

Hay dos diferencias básicas:

  1. $(document).ready() es parte de una librería javascript (jQuery), no es "javascript nativo", como ocurre con el evento window.onload

  2. El evento onload se lanza cuando se ha cargado completamente la página, con todo lo que ello conlleva (estilos, imágenes, etc...) mientras que la función $(document).ready() está disponible antes de que eso ocurra, cuando el árbol DOM del documento se ha completado.

De todas formas el enlace que has añadido a tu pregunta lo explica bien.

FerPeralta
  • 341
  • 1
  • 7
14

Window#load

Este evento es disparado una vez que se haya cargado el DOM y se haya terminado de parsear el documento en su totalidad. Esto incluye hojas de estilos, scripts y todo tipo de archivo multimedia (inágenes, vídeos, documentos embebidos, etc.).

jQuery#ready

Este es un evento personalizado de jQuery que es disparado cuando el árbol DOM haya sido cargado en su totalidad y todos los elementos estén disponibles en el DOM (sin tener en cuenta si los recursos a los cuales hacen referencia están disponibles). Este evento tiene mucha similitud con document#DOMContentLoaded.

document#DOMContentLoaded

Hace básicamente lo mismo que jQuery#ready. Este evento es disparado nativamente cuando el DOM está listo (sin tener en cuenta los recursos a los cuales se hace referencia).


jQuery#ready vs document#DOMContentLoaded

Al parecer, jquery#ready fue y es un polyfill para document#DOMContentLoaded. Ten en cuenta que jQuery salió a la luz cuando JavaScript era muy vago aún, sin funcionalidades que tiene hoy en día que facilitan las tareas.

Según la documentación de jQuery, dice lo siguiente:

Most browsers provide similar functionality in the form of a DOMContentLoaded event. However, jQuery's .ready() method differs in an important and useful way: If the DOM becomes ready and the browser fires DOMContentLoaded before the code calls .ready( handler ), the function handler will still be executed. In contrast, a DOMContentLoaded event listener added after the event fires is never executed.

Según jQuery, DOMContentLoaded es disparado antes que el navegador interprete jQuery#ready el handler para ready será ejecutado de todas maneras. Por otro lado, si se añade el handler para DOMContentLoaded luego que el evento ready es disparado éste nunca es ejecutado.

gugadev
  • 18,776
  • 1
  • 24
  • 49
10

Añadiendo a las respuestas que ya existen, cabe notar además que los eventos Window#loady document#DOMContentLoaded se ejecutan una sola vez. Si declaras una función condicionada a ese evento, y la declaración ocurre después de que se hayan gatillado, la función nunca se ejecutará.

Por la contrapartida, jQuery#ready se ejecutará cuando el documento esté listo, y se ejecutará "de inmediato" cuando el documento haya estado listo de antemano.

Finalmente, a diferencia de los eventos de window y document, jQuery#ready funciona, por dentro, como una promesa (por lo cual nunca es realmente "de inmediato"). Esto significa que el código dentro de un bloque $(document).ready() se ejecuta siempre en forma asíncrona sin importar si acaso se declaró cuando el DOM ya estaba cargado.

Esto se puede comprobar en el snippet siguiente. Un bloque $(document).ready() dentro de otro $(document).ready(), incluso a sabiendas de que el DOM está listo, no se ejecuta secuencialmente con los comandos que están un nivel más arriba:

console.log('antes de document.ready');
   
$(document).ready(function() {

  $(document).ready(function() {
      console.log('dentro de un segundo document.ready');
  });

  console.log('dentro de document.ready');
});

console.log('después de document.ready');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

En la práctica, puedes tener muchos bloques $(document).ready sin que éstos se afecten entre sí, por ejemplo cuando uno de ellos tira un error. Esto claramente no puedes hacerlo con los eventos de window y document.

ffflabs
  • 21,223
  • 25
  • 48
8

Las respuestas anteriores son muy buenas, sólo faltaría un ejemplo para clarificar la diferencia. Acá uno en fiddle

Una vez que la imagen se cargue en el cache del navegador la diferencia de carga es imperceptible. Se puede calcular la diferencia entre ambas cargas para conocer el tiempo de carga de los archivos externos.

lalengua
  • 640
  • 4
  • 13