tablas - script type= text/javascript src=
Cargar ordenamiento de etiquetas de script añadidas dinámicamente (2)
Me gustaría evitar el uso de la devolución de llamada de carga para resolver este problema ya que noté una degradación del rendimiento con mi aplicación.
Si quiere los archivos ordenados ... necesita esperar la carga de cada archivo. No hay forma de evitarlo
Aquí hay una función de utilidad que escribí una vez:
/**
* Utility : Resolves when a script has been loaded
*/
function include(url: string) {
return new Promise<{ script: HTMLScriptElement }>((resolve, reject) => {
var script = document.createElement(''script'');
script.type = ''text/javascript'';
script.src = url;
script.onload = function() {
resolve({ script });
};
document.getElementsByTagName(''head'')[0].appendChild(script);
});
}
Tengo una aplicación de mecanografía que agrega dinámicamente etiquetas de guiones que apuntan a los archivos JS. Debido a algunas restricciones, no puedo tener estas etiquetas de script definidas estáticamente en un archivo html, así que las agregué dinámicamente a través de una mecanografía como esta:
for (let src of jsFiles) {
let sTag = document.createElement(''script'');
sTag.type = ''text/javascript'';
sTag.src = src;
sTag.defer = true;
document.body.appendChild(script);
}
Ahora, me doy cuenta de que, cuando agrego etiquetas de scripts dinámicamente, no parecen ser una garantía en el orden en que se cargan. Desafortunadamente, la matriz jsFiles
tiene scripts que dependen el uno del otro. Por lo tanto, la segunda secuencia de comandos de la matriz solo se puede cargar después de que la primera esté completamente cargada. El segundo script hace referencia a una función que se define en el primero. ¿Existe alguna manera de especificar el orden en que se ordenan y ejecutan los scripts al agregarlos dinámicamente (de forma similar a cómo se realiza el pedido cuando se definen estáticamente las etiquetas de script en un archivo html)?
PD. Me gustaría evitar el uso de la devolución de llamada de carga para resolver este problema, ya que noté una degradación del rendimiento con mi aplicación. Mi segundo archivo de script es muy grande y supongo que causó la degradación.
Hay algunas formas de superar ese requisito. Por ahora puedo sugerir lo siguiente:
- Utilice una biblioteca para inyectar dependencias (módulos AMD o CommonJS)
- Cree la etiqueta del
script
programación y establezca el atributoasync = false
. - Cree la etiqueta de
script
programación y establezca la carga de devolución de llamada para reaccionar cuando la secuencia de comandos se haya cargado de forma asíncrona. El atributoasync = true
está establecido por defecto. (Ver ejemplo a continuación) - Si no le gustan las opciones anteriores y tiene permiso para modificar las secuencias de comandos para inyectar, agregue una línea al final de las secuencias de comandos con un
object
/array
que realice un seguimiento de las secuencias de comandos cargadas. - Como último recurso, puede buscar los guiones como texto, construir una
string
con los guiones en el orden requerido (ajustar cada guión de texto dentro de un IIFE ) y finalmente ejecutar el guión de texto a través del horrible y peligrosoeval()
. - Y la peor opción, use un
setInterval
para verificar si el script fue ejecutado. Agregué esta última opción solo porque he visto algunas soluciones usando esta mala técnica.
Si está trabajando en un gran proyecto, le recomendaría la primera opción. Pero si tiene un proyecto pequeño, puede optar por la tercera opción. ¿Por qué?
Consideremos que en la segunda opción, establecer el atributo async = false
hará que el navegador bloquee el procesamiento hasta que se haya ejecutado el script (mala práctica).
Quiero recomendar una lectura sobre los cargadores de scripts: ¡ Sumérgete en las aguas turbias de la carga de scripts , media hora de gasto!
Escribí un ejemplo de un pequeño módulo para administrar la inyección de scripts, y esta es la idea básica detrás:
let _scripts = [
''path/to/script1.js'',
''path/to/script2.js'',
''path/to/script3.js''
];
function createScriptTag() {
// gets the first script in the list
let script = _scripts.shift();
// all scripts were loaded
if (!script) return;
let js = document.createElement(''script'');
js.type = ''text/javascript'';
js.src = script;
js.onload = (event) => {
// loads the next script
createScriptTag();
};
let s = document.getElementsByTagName(''script'')[0];
s.parentNode.insertBefore(js, s);
}
En este plunker puedes probar la inyección de scripts de forma asincrónica en un orden específico:
La idea principal fue crear una API que le permita interactuar con las secuencias de comandos para inyectar, al exponer los siguientes métodos:
-
addScript
: recibe la url o unaArray
de URL de las secuencias de comandos. -
load
: ejecuta la tarea para cargar scripts en el orden específico. -
reset
: borre la matriz de scripts o cancele la carga de scripts. -
afterLoad
:afterLoad
llamada ejecutada después de que se haya cargado cada script. -
onComplete
:onComplete
llamada ejecutada después de que se hayan cargado todos los scripts.
Me gusta la interfaz fluida o el método de encadenamiento , luego construí el módulo de esa manera:
jsuLoader
.reset()
.addScript("script1.js")
.addScript(["script2.js", "script3.js"])
.afterLoad((src) => console.warn("> loaded from jsuLoader:", src))
.onComplete(() => console.info("* ALL SCRIPTS LOADED *"))
.load();
En el código anterior, afterLoad()
primero el archivo "script1.js"
y ejecutamos la devolución de llamada afterLoad()
, a continuación hacemos lo mismo con "script2.js"
y "script3.js"
y después de cargar todos los scripts, el onComplete()
se ejecuta la devolución de llamada.