Aún recuerdo mis tiempos de jQuery (si, esa librería ha sido una gran herramienta durante mucho tiempo) en que había que esperar a $(document).ready() para garantizar que el DOM y las librerías habían cargado para poder ejecutar código y que todo funcionara.
Pero cuando empezamos a poner el javascript al final del HTML (si, fuera del Header) para aliviar los tiempos de carga provocamos que en realidad no hiciera falta esperar, porque si se había cargado ese código es porque ya se había parseado todo el DOM.
Pero ¿eso quiere decir que el DOM está listo? ¿que se han cargado todos los elementos? Pues se han cargado todos los elementos renderizados en servidor, PERO actualmente hay mucho renderizado que se hace en cliente (React, Angular… )
Así que si queremos manipular el DOM, necesitamos garantizar que existe ese elemento que queremos manipular. Puede que se lance un script cuando el DOM está listo pero necesite esperar a que ese elemento esté disponible.
La solución habitual es hacer un bucle con setTimeout que hace una comprobación cada cierto tiempo y se lanza a si mismo si no encuentra el elemento para intentarlo de nuevo.
function check() {
if (!$('#elementId').size()){
setTimeout(check, 200);
} else {
// el código a ejecutar
}
}
Y esto puede que funcione, pero no es la manera más eficiente… y con los navegadores modernos puede que falle porque, cuando la pestaña / ventana no esté en primer plano puede que ahorren recursos y no corran ese código suficientemente «rápido».
Así que toca hacer una solución moderna para navegadores modernos, que no dependa de que la pestaña esté funcionando, o de que el timeout se ejecuta a tiempo. Y la respuesta es requestAnimationFrame
Se suele usar para animaciones, garantizando 60 refrescos por segundo. Pero también se puede usar para notificar al código que está esperando.
Así que usaremos algo como:
function check() {
if (!$('#elementId').size()){
window.requestAnimationFrame(check);
} else {
// el código a ejecutar
}
}
Y aunque en teoría podría parecer que este código se comprobaría el DOM cada 1/60 de segundo para comprobar el elemento buscado, solo se hará una vez, cuando el elemento sea renderizado.
Y así es la manera adecuada de esperar a un elemento de DOM en los navegadores modernos.
Mas info: Swizec