javascript - sobre - Cómo saber si una etiqueta<script> no se pudo cargar
script type= text/javascript src= (14)
Aquí hay otra solución basada en JQuery sin temporizadores:
<script type="text/javascript">
function loadScript(url, onsuccess, onerror) {
$.get(url)
.done(function() {
// File/url exists
console.log("JS Loader: file exists, executing $.getScript "+url)
$.getScript(url, function() {
if (onsuccess) {
console.log("JS Loader: Ok, loaded. Calling onsuccess() for " + url);
onsuccess();
console.log("JS Loader: done with onsuccess() for " + url);
} else {
console.log("JS Loader: Ok, loaded, no onsuccess() callback " + url)
}
});
}).fail(function() {
// File/url does not exist
if (onerror) {
console.error("JS Loader: probably 404 not found. Not calling $.getScript. Calling onerror() for " + url);
onerror();
console.error("JS Loader: done with onerror() for " + url);
} else {
console.error("JS Loader: probably 404 not found. Not calling $.getScript. No onerror() callback " + url);
}
});
}
</script>
Gracias a: https://stackoverflow.com/a/14691735/1243926
Uso de muestra (muestra original de la $.getScript de $.getScript ):
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery.getScript demo</title>
<style>
.block {
background-color: blue;
width: 150px;
height: 70px;
margin: 10px;
}
</style>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
</head>
<body>
<button id="go">» Run</button>
<div class="block"></div>
<script>
function loadScript(url, onsuccess, onerror) {
$.get(url)
.done(function() {
// File/url exists
console.log("JS Loader: file exists, executing $.getScript "+url)
$.getScript(url, function() {
if (onsuccess) {
console.log("JS Loader: Ok, loaded. Calling onsuccess() for " + url);
onsuccess();
console.log("JS Loader: done with onsuccess() for " + url);
} else {
console.log("JS Loader: Ok, loaded, no onsuccess() callback " + url)
}
});
}).fail(function() {
// File/url does not exist
if (onerror) {
console.error("JS Loader: probably 404 not found. Not calling $.getScript. Calling onerror() for " + url);
onerror();
console.error("JS Loader: done with onerror() for " + url);
} else {
console.error("JS Loader: probably 404 not found. Not calling $.getScript. No onerror() callback " + url);
}
});
}
loadScript("https://raw.github.com/jquery/jquery-color/master/jquery.color.js", function() {
console.log("loaded jquery-color");
$( "#go" ).click(function() {
$( ".block" )
.animate({
backgroundColor: "rgb(255, 180, 180)"
}, 1000 )
.delay( 500 )
.animate({
backgroundColor: "olive"
}, 1000 )
.delay( 500 )
.animate({
backgroundColor: "#00f"
}, 1000 );
});
}, function() { console.error("Cannot load jquery-color"); });
</script>
</body>
</html>
Estoy agregando dinámicamente etiquetas <script>
al <head>
una página, y me gustaría poder decir si la carga falló de alguna manera: un 404, un error de script en el script cargado, lo que sea.
En Firefox, esto funciona:
var script_tag = document.createElement(''script'');
script_tag.setAttribute(''type'', ''text/javascript'');
script_tag.setAttribute(''src'', ''http://fail.org/nonexistant.js'');
script_tag.onerror = function() { alert("Loading failed!"); }
document.getElementsByTagName(''head'')[0].appendChild(script_tag);
Sin embargo, esto no funciona en IE o Safari.
¿Alguien sabe de una manera de hacer que esto funcione en buscadores que no sean Firefox?
(No creo que una solución que requiera colocar un código especial dentro de los archivos .js sea buena. Es poco elegante e inflexible).
Bueno, la única forma en que puedo pensar en hacer todo lo que quieras es bastante feo. Primero realice una llamada AJAX para recuperar el contenido del archivo Javascript. Cuando esto se complete, puede verificar el código de estado para decidir si fue exitoso o no. A continuación, tome el responseText del objeto xhr y envuélvalo en try / catch, cree dinámicamente una etiqueta de script, y para IE puede establecer la propiedad de texto de la etiqueta de script en el texto JS, en todos los demás navegadores usted debería poder anexar un nodo de texto con los contenidos a la etiqueta de script. Si hay algún código que espera que una etiqueta de secuencia de comandos realmente contenga la ubicación src del archivo, esto no funcionará, pero debería estar bien para la mayoría de las situaciones. Feo, pero funcionará. Puedes echar un vistazo a mi ejemplo rápido y sucio aquí: http://pastie.org/829775
El guión de Erwinus funciona muy bien, pero no está muy codificado. Me tomé la libertad de limpiarlo y descifrar lo que estaba haciendo. Hice estos cambios:
- Nombres de variables significativas
- Uso del
prototype
. -
require()
usa una variable de argumento - No se devuelven mensajes de
alert()
de forma predeterminada - Se corrigieron algunos errores de sintaxis y problemas de alcance que estaba obteniendo
Gracias de nuevo a Erwinus, la funcionalidad en sí misma es perfecta.
function ScriptLoader() {
}
ScriptLoader.prototype = {
timer: function (times, // number of times to try
delay, // delay per try
delayMore, // extra delay per try (additional to delay)
test, // called each try, timer stops if this returns true
failure, // called on failure
result // used internally, shouldn''t be passed
) {
var me = this;
if (times == -1 || times > 0) {
setTimeout(function () {
result = (test()) ? 1 : 0;
me.timer((result) ? 0 : (times > 0) ? --times : times, delay + ((delayMore) ? delayMore : 0), delayMore, test, failure, result);
}, (result || delay < 0) ? 0.1 : delay);
} else if (typeof failure == ''function'') {
setTimeout(failure, 1);
}
},
addEvent: function (el, eventName, eventFunc) {
if (typeof el != ''object'') {
return false;
}
if (el.addEventListener) {
el.addEventListener(eventName, eventFunc, false);
return true;
}
if (el.attachEvent) {
el.attachEvent("on" + eventName, eventFunc);
return true;
}
return false;
},
// add script to dom
require: function (url, args) {
var me = this;
args = args || {};
var scriptTag = document.createElement(''script'');
var headTag = document.getElementsByTagName(''head'')[0];
if (!headTag) {
return false;
}
setTimeout(function () {
var f = (typeof args.success == ''function'') ? args.success : function () {
};
args.failure = (typeof args.failure == ''function'') ? args.failure : function () {
};
var fail = function () {
if (!scriptTag.__es) {
scriptTag.__es = true;
scriptTag.id = ''failed'';
args.failure(scriptTag);
}
};
scriptTag.onload = function () {
scriptTag.id = ''loaded'';
f(scriptTag);
};
scriptTag.type = ''text/javascript'';
scriptTag.async = (typeof args.async == ''boolean'') ? args.async : false;
scriptTag.charset = ''utf-8'';
me.__es = false;
me.addEvent(scriptTag, ''error'', fail); // when supported
// when error event is not supported fall back to timer
me.timer(15, 1000, 0, function () {
return (scriptTag.id == ''loaded'');
}, function () {
if (scriptTag.id != ''loaded'') {
fail();
}
});
scriptTag.src = url;
setTimeout(function () {
try {
headTag.appendChild(scriptTag);
} catch (e) {
fail();
}
}, 1);
}, (typeof args.delay == ''number'') ? args.delay : 1);
return true;
}
};
$(document).ready(function () {
var loader = new ScriptLoader();
loader.require(''resources/templates.js'', {
async: true, success: function () {
alert(''loaded'');
}, failure: function () {
alert(''NOT loaded'');
}
});
});
Espero que esto no sea downvoted, porque en circunstancias especiales, es la forma más confiable de resolver el problema. Cada vez que el servidor le permite obtener un recurso de Javascript utilizando CORS ( http://en.wikipedia.org/wiki/Cross-origin_resource_sharing ), tiene una gran variedad de opciones para hacerlo.
El uso de XMLHttpRequest para buscar recursos funcionará en todos los navegadores modernos, incluido IE. Ya que está buscando cargar Javascript, tiene Javascript disponible para usted en primer lugar. Puede rastrear el progreso usando readyState ( http://en.wikipedia.org/wiki/XMLHttpRequest#The_onreadystatechange_event_listener ). Finalmente, una vez que reciba el contenido del archivo, puede ejecutarlo con eval (). Sí, dije eval - porque en lo que respecta a seguridad no es diferente de cargar el script normalmente. De hecho, John Resig sugiere una técnica similar para tener etiquetas más bonitas ( http://ejohn.org/blog/degrading-script-tags/ ).
Este método también le permite separar la carga de la evaluación y ejecutar funciones antes y después de la evaluación. Resulta muy útil cuando carga scripts en paralelo pero los evalúa uno tras otro, algo que los navegadores pueden hacer fácilmente cuando coloca las etiquetas en HTML, pero no le permiten agregar scripts en tiempo de ejecución con Javascript.
CORS también es preferible a JSONP para cargar scripts ( http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests ). Sin embargo, si está desarrollando sus propios widgets de terceros para ser integrados en otros sitios, debería cargar los archivos Javascript de su propio dominio en su propio iframe (nuevamente, usando AJAX)
En breve:
Intenta ver si puedes cargar el recurso usando AJAX GET
Use eval después de que se haya cargado correctamente
Para mejorarlo:
Echa un vistazo a los encabezados de control de caché que se envían
Mire de otra manera el almacenamiento en caché del contenido en localStorage, si necesita
Echa un vistazo al "Javascript degradante" de Resig para obtener un código más limpio
Echa un vistazo a require.js
Este truco funcionó para mí, aunque admito que probablemente esta no sea la mejor manera de resolver este problema. En lugar de intentar esto, debería ver por qué los javascripts no se están cargando. Intente mantener una copia local de la secuencia de comandos en su servidor, etc. o consulte con el proveedor de terceros desde donde está tratando de descargar la secuencia de comandos.
De todos modos, aquí está la solución alternativa: 1) Inicializar una variable en falso 2) Establecerlo en verdadero cuando se carga javascript (usando el atributo onload) 3) comprobar si la variable es verdadera o falsa una vez que el cuerpo HTML se ha cargado
<html>
<head>
<script>
var scriptLoaded = false;
function checkScriptLoaded() {
if (scriptLoaded) {
// do something here
} else {
// do something else here!
}
}
</script>
<script src="http://some-external-script.js" onload="scriptLoaded=true;" />
</head>
<body onload="checkScriptLoaded()">
<p>My Test Page!</p>
</body>
</html>
La razón por la que no funciona en Safari es porque está usando la sintaxis de los atributos. Esto funcionará bien sin embargo:
script_tag.addEventListener(''error'', function(){/*...*/}, true);
... excepto en IE.
Si desea verificar el script ejecutado con éxito, simplemente establezca una variable usando ese script y verifique que esté establecido en el código externo.
No hay ningún evento de error para la etiqueta de script. Puede ver cuándo es exitoso y asumir que no se ha cargado después de un tiempo de espera:
<script type="text/javascript" onload="loaded=1" src="....js"></script>
No sé cómo hacer que esto funcione, pero si quieres cargar JavaScript de forma dinámica, sé que cargar un JavaScript con jQuery ejecutará el script, o simplemente cargar JavaScript con cualquier función AJAX y eval () debería funcionar .
Para comprobar si el javascript en nonexistant.js
no var isExecuted = true;
ningún error, debe agregar una variable dentro de http://fail.org/nonexistant.js
como var isExecuted = true;
y luego verifique si existe cuando se carga la etiqueta del script.
Sin embargo, si solo desea comprobar que el nonexistant.js
devuelto sin un 404 (lo que significa que existe), puede probar con una variable isLoaded
...
var isExecuted = false;
var isLoaded = false;
script_tag.onload = script_tag.onreadystatechange = function() {
if(!this.readyState ||
this.readyState == "loaded" || this.readyState == "complete") {
// script successfully loaded
isLoaded = true;
if(isExecuted) // no error
}
}
Esto cubrirá ambos casos.
Sé que este es un hilo viejo, pero tengo una buena solución para ti (creo). Está copiado de una clase mía, que maneja todas las cosas de AJAX.
Cuando no se puede cargar la secuencia de comandos, se establece un controlador de errores, pero cuando el controlador de errores no es compatible, se recurre a un temporizador que comprueba los errores durante 15 segundos.
function jsLoader()
{
var o = this;
// simple unstopable repeat timer, when t=-1 means endless, when function f() returns true it can be stopped
o.timer = function(t, i, d, f, fend, b)
{
if( t == -1 || t > 0 )
{
setTimeout(function() {
b=(f()) ? 1 : 0;
o.timer((b) ? 0 : (t>0) ? --t : t, i+((d) ? d : 0), d, f, fend,b );
}, (b || i < 0) ? 0.1 : i);
}
else if(typeof fend == ''function'')
{
setTimeout(fend, 1);
}
};
o.addEvent = function(el, eventName, eventFunc)
{
if(typeof el != ''object'')
{
return false;
}
if(el.addEventListener)
{
el.addEventListener (eventName, eventFunc, false);
return true;
}
if(el.attachEvent)
{
el.attachEvent("on" + eventName, eventFunc);
return true;
}
return false;
};
// add script to dom
o.require = function(s, delay, baSync, fCallback, fErr)
{
var oo = document.createElement(''script''),
oHead = document.getElementsByTagName(''head'')[0];
if(!oHead)
{
return false;
}
setTimeout( function() {
var f = (typeof fCallback == ''function'') ? fCallback : function(){};
fErr = (typeof fErr == ''function'') ? fErr : function(){
alert(''require: Cannot load resource -''+s);
},
fe = function(){
if(!oo.__es)
{
oo.__es = true;
oo.id = ''failed'';
fErr(oo);
}
};
oo.onload = function() {
oo.id = ''loaded'';
f(oo);
};
oo.type = ''text/javascript'';
oo.async = (typeof baSync == ''boolean'') ? baSync : false;
oo.charset = ''utf-8'';
o.__es = false;
o.addEvent( oo, ''error'', fe ); // when supported
// when error event is not supported fall back to timer
o.timer(15, 1000, 0, function() {
return (oo.id == ''loaded'');
}, function(){
if(oo.id != ''loaded''){
fe();
}
});
oo.src = s;
setTimeout(function() {
try{
oHead.appendChild(oo);
}catch(e){
fe();
}
},1);
}, (typeof delay == ''number'') ? delay : 1);
return true;
};
}
$(document).ready( function()
{
var ol = new jsLoader();
ol.require(''myscript.js'', 800, true, function(){
alert(''loaded'');
}, function() {
alert(''NOT loaded'');
});
});
Se propuso establecer un tiempo de espera y luego asumir la falla de carga después de un tiempo de espera.
setTimeout(fireCustomOnerror, 4000);
El problema con ese enfoque es que la suposición se basa en el azar. Después de que expira el tiempo de espera, la solicitud aún está pendiente. La solicitud de la secuencia de comandos pendiente puede cargarse, incluso después de que el programador suponga que no se producirá la carga.
Si la solicitud se puede cancelar, entonces el programa podría esperar un período, luego cancelar la solicitud.
Si solo te interesan los navegadores html5, puedes utilizar el evento de error (ya que esto es solo para el manejo de errores, debería estar bien solo apoyar esto en los navegadores de próxima generación para KISS EN MOVIMIENTO).
De la especificación:
Si el valor del atributo src es la cadena vacía o si no se pudo resolver, el agente de usuario debe poner en cola una tarea para activar un evento simple denominado error en el elemento y cancelar estos pasos.
~
Si la carga generó un error (por ejemplo, un error de DNS o un error de HTTP 404), la ejecución del bloque de scripts solo debe consistir en disparar un evento simple denominado error en el elemento.
Esto significa que no tiene que realizar ningún sondeo propenso a errores y puede combinarlo con los atributos async y defer para asegurarse de que el script no está bloqueando la representación de la página:
El atributo defer se puede especificar incluso si se especifica el atributo async, para hacer que los navegadores web heredados que solo admiten diferir (y no asincrónico) vuelvan al comportamiento diferido en lugar del comportamiento de bloqueo síncrono que es el predeterminado.
Más sobre http://www.w3.org/TR/html5/scripting-1.html#script
mi solución limpia de trabajo (2017)
function loaderScript(scriptUrl){
return new Promise(function (res, rej) {
let script = document.createElement(''script'');
script.src = scriptUrl;
script.type = ''text/javascript'';
script.onError = rej;
script.async = true;
script.onload = res;
script.addEventListener(''error'',rej);
script.addEventListener(''load'',res);
document.head.appendChild(script);
})
}
puede incluir una función en el archivo de script java, si es posible, como check () {var report; informe = True} luego ejecute esta función si la función no se ejecuta o no responde, probablemente, el script no se carga; listo para usar . el atributo onload también es útil.