Inyectar scripts de forma dinamica

A través de JavaScript se puede crear casi cualquier elemento HMTL e inyectarlo después en el DOM de la pagina. El elemento script no es una una excepción. Un script puede moverse, eliminarse y también crearse mediante programación en JavaScript. Un script puede crearse e incluirse en el DOM utilizando los métodos standard para ello:

var nuevoScript = document.createElement("script");
nuevoScript.type = "text/javascript";
script.src = "/ruta/al/fichero.js";
document.getElementByTagName("head')[0].appendChild(nuevoScript);

Con el código anterior incluiremos en el <head> el archivo fichero.js. El fichero empezará a descargarse tan pronto sea inyectado en el DOM. Lo importante aquí es saber que fichero.js es descargado y ejecutado sin bloquear cualquier otro proceso de la página sin importar donde coloquemos el script. Se puede incluso colocar en el <head> del documento sin afectar al resto de la página (a parte, por supuesto, de utilizar una conexión HTTP para la descarga del fichero).

Es mucho más seguro insertar el script en <head> en vez de en el <body> especialmente si el código se ejecuta durante la carga de la página. Internet Explorer puede dar algún problema …

Utilizar esta técnica cuando queremos descargar un solo script está muy bien. Pero si se descargan varios script (a no ser que no tengan ninguna relación entre ellos) y unos dependen de otros puede suponer un problema ya que no se garantiza el orden de descarga ni ejecución. Si incluimos dos scripts, por ejemplo ficheroA.js y ficheroB.js, y ficheroB.js llama a una función que se encuentra en ficheroA.js, nada garantiza (a pesar de que en código hayas puesto uno antes que el otro) que cuando ficheroB.js llame a la función de ficheroA.js se produzca un error JavaScript por la sencilla razón de que ficheroA.js aún no se había descargado.

La gran mayoría de los navegadores lanzan el evento load cuando el script se ha descargado. Se puede por lo tanto escuchar dicho evento:

nuevoScript.onload = function(){
    iniciarAplicacion();
}

Internet Explorer gestiona la carga de los scripts de una forma alternativa y el evento que lanza es readystatechange.  El script descargado tiene la propiedad readyState que va cambiando durante la descarga. Nos interesa comprobar dos de los cinco valores que esta propiedad puede tener: “loaded” y “complete“.

var nuevoScript = document.createElement("script");
//Internet Explorer
nuevoScript.onreadystatechange = function(){
    if(nuevoScript.readyState == "loaded" || nuevoScript.readyState == "complete"){
        nuevoScript.onreadystatechange = null; //evita que se lance dos veces
        iniciarAplicacion();
    }
}

Así que si juntamos las dos implementaciones y utilizamos feature detection tendremos la siguiente función a la que le podemos pasar una función callback a ejecutar una vez descargado el fichero:

function cargarScript(url, callback){
var nuevoScript = document.createElement("script");
nuevoScript.type = "text/javascript";
if (nuevoScript.readyState){ //Internet Explorer
nuevoScript.onreadystatechange = function(){
if (nuevoScript.readyState == "loaded" || nuevoScript.readyState == "complete"){
nuevoScript.onreadystatechange = null; //evita que se llame mas de una vez
callback();
}
}
} else {//otros navegadores
nuevoScript.onload = function(){
callback();
}
}
nuevoScript.src = url;
document.getElementsByTagName("head")[0].appendChild(nuevoScript);
}

view raw
cargarScript.js
hosted with ❤ by GitHub

cargarScript("/ruta/al/ficheroA.js", function(){
cargarScript("/ruta/al/ficheroB.js", function(){
iniciarAplicacion(); // "iniciarAplicacion" está en ficheroB.js, pero en él hay referencias a ficheroA.js
//En este punto se pueden utilizar los dos JS sin miedo
})
});

Lo importante es darse cuenta que la función callback podría ser la misma cargarScript de nuevo e ir creando un hilo para asegurarnos que las funciones a las que se llaman están disponibles.

Antes de llamar a iniciarAplicacion() se espera a que ficheroA.js y ficheroB.js esten totalmente descargados. Y habremos descargados dos scripts de forma no bloqueante que era de lo que se trataba.

Si estás utilizando mucho este patrón de descarga de scripts, lo mejor es utilizar librerías como http://clickalicious.github.io/Lazyload.js/

Inyectar scripts de forma dinamica

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s