Comment savoir si une balise <script> n'a pas pu se charger


112

J'ajoute dynamiquement des <script>balises à une page <head>et j'aimerais pouvoir dire si le chargement a échoué d'une manière ou d'une autre - un 404, une erreur de script dans le script chargé, peu importe.

Dans Firefox, cela fonctionne:

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);

Cependant, cela ne fonctionne pas dans IE ou Safari.

Quelqu'un connaît-il un moyen de faire fonctionner cela dans des navigateurs autres que Firefox?

(Je ne pense pas qu'une solution qui nécessite de placer un code spécial dans les fichiers .js soit une bonne solution. Elle est inélégante et inflexible.)


4
Grand site Web, chargement automatique des dépendances pour le contenu chargé via ajax. if+ le sondage est une crotte ennuyeuse que je ne veux pas avoir à mettre dans tous les JS.
David

2
Vous pouvez également vérifier si le chargement échoue lors de la création d'une requête JSONP à l'aide de l'injection de balises de script ...
schellsan

Réponses:


36

Il n'y a pas d'événement d'erreur pour la balise de script. Vous pouvez dire quand il réussit et supposer qu'il ne s'est pas chargé après un délai:

<script type="text/javascript" onload="loaded=1" src="....js"></script>

7
L'écouteur "onload" sera déclenché même s'il y a une erreur javascript.
Luca Matteis le

38
Eh bien, oui si le fichier LOADS et qu'il y a une erreur dans le fichier lui-même, mais si le fichier n'est pas servi, le chargement ne se déclenchera jamais.
Diodeus - James MacFarlane

1
oui, c'est vrai, c'est pourquoi j'ai demandé à être plus précis sur le type d'erreur qu'il recherchait.
Luca Matteis le

1
Mais le délai doit être fourni par le codeur de la page, n'est-ce pas? Ainsi, le codeur peut choisir un délai d'expiration différent pour le navigateur, supposer que le chargement du script a expiré, puis le faire réussir un peu plus tard. Ou pas?
hippietrail

6
Il y a une erreur evnt pour la balise script. Il se déclenchera lorsque la ressource est introuvable.
Nguyen Tran

24

Si vous ne vous souciez que des navigateurs html5, vous pouvez utiliser l'événement d'erreur (puisque ce n'est que pour la gestion des erreurs, il devrait être correct de ne prendre en charge cela que sur les navigateurs de nouvelle génération pour KISS IMHO).

De la spécification:

Si la valeur de l'attribut src est la chaîne vide ou si elle n'a pas pu être résolue, alors l'agent utilisateur doit mettre en file d'attente une tâche pour déclencher un événement simple nommé erreur au niveau de l'élément et abandonner ces étapes.

~

Si le chargement a entraîné une erreur (par exemple une erreur DNS, ou une erreur HTTP 404) L'exécution du bloc de script doit simplement consister à déclencher un événement simple nommé error sur l'élément.

Cela signifie que vous n'avez pas à effectuer d'interrogation sujette aux erreurs et que vous pouvez le combiner avec l'attribut async et defer pour vous assurer que le script ne bloque pas le rendu de la page:

L'attribut defer peut être spécifié même si l'attribut async est spécifié, pour que les navigateurs Web hérités qui ne prennent en charge que le différé (et non async) reviennent au comportement de différé au lieu du comportement de blocage synchrone qui est la valeur par défaut.

Plus d'informations sur http://www.w3.org/TR/html5/scripting-1.html#script


1
Une idée d'implémentations JSONP, comme celle de jQuery, prend en charge cela? Tout ce que j'ai lu ici sur la détection des échecs de chargement de JSONP indique qu'il ne peut pas être détecté, mais un délai d'expiration peut être une solution de contournement, et un délai d'expiration a été ajouté à une version récente de JSONP. Il semble que cette réponse offre quelque chose de mieux que le délai d'expiration - est-ce correct?
hippietrail

1
exemple possible s'il vous plaît?
rogerdpack

13
<script src="nonexistent.js" onerror="alert('error!')"></script> fiddle
Rudey

@Rudey Uncaught SyntaxError: Unexpected token '<'(dans le dernier Chrome)
daleyjem le

@daleyjem semble avoir tenté de mettre une balise HTML dans JavaScript. <script src="nonexistent.js" onerror="alert('error!')"></script>devrait aller dans votre fichier HTML, pas dans JS.
Rudey

21

Le script d'Erwinus fonctionne très bien, mais n'est pas très clairement codé. J'ai pris la liberté de le nettoyer et de déchiffrer ce qu'il faisait. J'ai apporté ces modifications:

  • Noms de variables significatifs
  • Utilisation de prototype.
  • require() utilise une variable d'argument
  • Aucun alert()message n'est renvoyé par défaut
  • Correction de certaines erreurs de syntaxe et problèmes de portée que je recevais

Merci encore à Erwinus, la fonctionnalité elle-même est parfaite.

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');
        }
    });
});

4
J'ai été obligé d'utiliser $ .getScript de jQuery , car cette fonction a échoué pour les scripts mis en cache dans MSIE8-, malheureusement
Zathrus Writer

@ZathrusWriter c'est probablement une meilleure idée, merci de nous l'avoir fait savoir! Vous pourriez probablement ajouter un int aléatoire à l'url dans ce code et cela supprimerait la mise en cache.
Aram Kocharyan

2
Oui Aram, cela ferait certainement l'affaire, mais cela invaliderait également la mise en cache du navigateur, donc la surcharge dans un tel cas ne vaut probablement pas vraiment la peine;)
Zathrus Writer

@ZathrusWriter, alors comment fonctionne le fonctionnement de l'implémentation jQuery?
Pacerier

@Pacerier désolé, je ne suis pas un développeur principal de jQuery, donc je ne peux pas vraiment répondre à cela
Zathrus Writer

18

ma solution propre de travail (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);
 })

}

Comme Martin l'a souligné, utilisé comme ça:

const event = loaderScript("myscript.js")
  .then(() => { console.log("loaded"); })
  .catch(() => { console.log("error"); });

OU

try{
 await loaderScript("myscript.js")
 console.log("loaded"); 
}catch{
 console.log("error");
}

1
Utilisez-le comme suit:loaderScript("myscript.js").then(() => { console.log("loaded"); }).catch(() => { console.log("error"); });
Martin Wantke

17

Je sais que c'est un vieux fil mais j'ai une bonne solution pour vous (je pense). Il est copié à partir d'une de mes classes, qui gère tous les éléments AJAX.

Lorsque le script ne peut pas être chargé, il définit un gestionnaire d'erreurs, mais lorsque le gestionnaire d'erreurs n'est pas pris en charge, il revient à un minuteur qui vérifie les erreurs pendant 15 secondes.

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');
    });
});

4
... d'où vient jQuery?
Naftali aka Neal

1
Et aussi, c'est une solution multi-navigateurs ;-)
Codebeat

1
@Erwinus Je n'ai pas vérifié les en-têtes, c'était juste une vérification rapide entre les navigateurs que j'ai effectuée et $ .getScript a toujours fonctionné sans problème, donc je suis resté avec lui ... vous êtes invités à essayer vous-même, j'utilise W7 et XAMPP here
Zathrus Writer

19
Que cela fonctionne ou non, c'est sacrément pénible à lire - sans parler de débogage. C'est un formatage assez médiocre et un style de codage vraiment atroce. La dénomination des variables à elle seule est un gâchis.
Thor84no

7
Si vous ne voyez pas la valeur du code lisible (et vous pouvez le rendre lisible sans aucune modification du code réellement exécuté), alors je suis désolé pour chaque personne qui doit travailler avec vous et votre code.
Thor84no

10

Pour vérifier si le javascript nonexistant.jsn'a renvoyé aucune erreur, vous devez ajouter une variable à l'intérieur http://fail.org/nonexistant.jscomme var isExecuted = true;, puis vérifier si elle existe lorsque la balise de script est chargée.

Cependant, si vous voulez seulement vérifier que le nonexistant.jsrenvoyé sans 404 (ce qui signifie qu'il existe), vous pouvez essayer avec une isLoadedvariable ...

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
    }
}

Cela couvrira les deux cas.


1
Cela fonctionne, mais ne fait pas vraiment ce que je veux - un échec dans ce cas ne déclencherait jamais un événement. Je ne veux pas avoir à interroger une variable et, si elle est toujours fausse après quelques secondes, déclenche le rappel en cas d'échec.
David

Quel type d'erreur essayez-vous de récupérer? Échec du chargement? Échec de l'exécution du javascript dans nonexstant.js? Erreur de réponse HTTP? Veuillez être plus descriptif.
Luca Matteis

Tout ce qui précède serait bon. Cependant, je me soucie spécifiquement d'une erreur 404.
David

404, ce qui signifie que vous voulez vérifier si le fichier nonexistant.js n'existe pas? Mais si vous voulez vérifier s'il n'a renvoyé aucune erreur?
Luca Matteis le

Hey David, vous devriez être en mesure de supposer que si this.readyState / ... n'est pas vrai, le script n'a pas pu se charger. Fondamentalement, un onError.
Cody

7

J'espère que cela ne sera pas critiqué, car dans des circonstances particulières, c'est le moyen le plus fiable de résoudre le problème. Chaque fois que le serveur vous permet d'obtenir une ressource Javascript à l'aide de CORS ( http://en.wikipedia.org/wiki/Cross-origin_resource_sharing ), vous disposez d'un large éventail d'options pour le faire.

L'utilisation de XMLHttpRequest pour récupérer des ressources fonctionnera sur tous les navigateurs modernes, y compris IE. Puisque vous cherchez à charger Javascript, vous disposez en premier lieu de Javascript. Vous pouvez suivre la progression en utilisant readyState ( http://en.wikipedia.org/wiki/XMLHttpRequest#The_onreadystatechange_event_listener ). Enfin, une fois que vous avez reçu le contenu du fichier, vous pouvez l'exécuter avec eval (). Oui, j'ai dit eval - parce que sur le plan de la sécurité, cela ne diffère pas du chargement normal du script. En fait, une technique similaire est suggérée par John Resig pour avoir des balises plus agréables ( http://ejohn.org/blog/degrading-script-tags/ ).

Cette méthode vous permet également de séparer le chargement de l'évaluation et d'exécuter des fonctions avant et après l'évaluation. Cela devient très utile lors du chargement de scripts en parallèle mais en les évaluant l'un après l'autre - ce que les navigateurs peuvent faire facilement lorsque vous placez les balises en HTML, mais ne vous le laissez pas en ajoutant des scripts au moment de l'exécution avec Javascript.

CORS est également préférable à JSONP pour le chargement de scripts ( http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests ). Cependant, si vous développez vos propres widgets tiers à intégrer dans d'autres sites, vous devez en fait charger les fichiers Javascript de votre propre domaine dans votre propre iframe (encore une fois, en utilisant AJAX)

En bref:

  1. Essayez de voir si vous pouvez charger la ressource en utilisant AJAX GET

  2. Utilisez eval après son chargement

Pour l'améliorer:

  1. Vérifiez les en-têtes de contrôle du cache envoyés

  2. Recherchez autrement la mise en cache du contenu dans localStorage, si vous devez

  3. Consultez le «JavaScript dégradant» de Resig pour un code plus propre

  4. Découvrez require.js


NB que cette manière nécessite que le serveur d'origine ait activé CORS, ce qui n'est pas toujours le cas ou contrôlable: |
rogerdpack

5

Cette astuce a fonctionné pour moi, même si j'avoue que ce n'est probablement pas la meilleure façon de résoudre ce problème. Au lieu d'essayer cela, vous devriez voir pourquoi les javascripts ne se chargent pas. Essayez de conserver une copie locale du script sur votre serveur, etc. ou vérifiez auprès du fournisseur tiers à partir duquel vous essayez de télécharger le script.

Quoi qu'il en soit, voici la solution de contournement: 1) Initialisez une variable sur false 2) Définissez-le sur true lorsque le javascript se charge (en utilisant l'attribut onload) 3) vérifiez si la variable est vraie ou fausse une fois le corps HTML chargé

<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>

1
Et si le script est toujours en cours de chargement? Comment savoir si le fichier n'a pas été trouvé ou si vous devez simplement attendre?
osa

Cette solution fonctionne dans mes tests, tant que la balise de script est placée directement dans la source du document. L'événement onload du document ne se déclenche pas tant que toutes les ressources référencées dans la source de la page n'ont pas déjà été chargées (ou ont échoué). Si vous devez insérer des scripts dans le DOM plus tard, cependant, vous avez besoin d'une autre approche.
Jamey Sharp

Excellente solution. Je ne comprends pas pourquoi il n'a pas été voté.
Lotfi

Cela suppose que le script sera chargé de manière synchrone bloquant tout le reste, ce qui n'est pas toujours vrai. En fait, ce n'est pas une méthode recommandée pour charger des scripts.
Vitim.us

4

Voici une autre solution basée sur JQuery sans aucun minuteur:

<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>

Merci à: https://stackoverflow.com/a/14691735/1243926

Exemple d'utilisation (exemple original de la documentation JQuery 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">&raquo; 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>

Nice Sergey! Donc, vous utilisez .get () pour vérifier si le fichier existe et .getScript () pour vérifier s'il peut être exécuté / chargé sans erreur?
jjwdesign

2
Oui. Si je me souviens bien, cette approche a des limites: vous ne pourrez pas charger de nombreux scripts de cette manière --- si je me souviens bien, à cause des restrictions de script inter-domaines.
osa

Le problème avec l'utilisation de jQuery (ou d'une autre bibliothèque) est que vous devez d'abord charger cette bibliothèque. Alors, comment vérifier si cette bibliothèque n'a pas pu se charger?
Pacerier

J'ai également adopté cette approche, mais je recommande d'utiliser cache:truepour l'appel $ .getScript (c'est désactivé par défaut). De cette façon, pour la plupart des requêtes, il utilise automatiquement la version en cache pour l'appel getScript (vous économisant de la latence)
Laurens Rietveld

2

Cela peut être fait en toute sécurité en utilisant des promesses

function loadScript(src) {
  return new Promise(function(resolve, reject) {
    let script = document.createElement('script');
    script.src = src;

    script.onload = () => resolve(script);
    script.onerror = () => reject(new Error("Script load error: " + src));

    document.head.append(script);
  });
}

et utiliser comme ça

let promise = loadScript("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js");

promise.then(
  script => alert(`${script.src} is loaded!`),
  error => alert(`Error: ${error.message}`)
);

1

La raison pour laquelle cela ne fonctionne pas dans Safari est que vous utilisez la syntaxe d'attribut. Cela fonctionnera bien cependant:

script_tag.addEventListener('error', function(){/*...*/}, true);

... sauf dans IE.

Si vous voulez vérifier le script exécuté avec succès, définissez simplement une variable à l'aide de ce script et vérifiez qu'elle est définie dans le code externe.


Cela ne fait aucune différence pour Safari - il ne déclenche toujours pas le gestionnaire d'erreurs.
David

J'ai eu un problème avec un gestionnaire onclick en safari et c'est ce qui l'a résolu, alors j'ai pensé que ce serait la même chose pour onerror aussi. Apparemment pas ...

1
Cela devrait-il également fonctionner pour les balises de script incluses statiquement, ou uniquement celles injectées dynamiquement? J'ai juste essayé de l'utiliser pour détecter si jQuery n'a pas pu se charger mais cela n'a pas fonctionné. Je ne sais pas si je le fais mal ou si cela ne fonctionne tout simplement pas dans ce cas.
hippietrail

1
@hippietrail - un écouteur d'événement ne fonctionnera jamais sur un HTML statique <script>. Si vous essayez de l'ajouter avant, vous obtenez une erreur indiquant que la balise n'existe pas, et si vous l'ajoutez après, le script est déjà exécuté et a déclenché ses événements. Le seul moyen est de rechercher les effets secondaires causés par le script.

Merci flussence. Dommage que cela ne fonctionne que pour 404, pas pour les erreurs JS. La définition d'une variable dans le script n'est pas toujours réalisable.
Jo Liss

1

événement onerror

* Mise à jour d'août 2017: onerror est déclenché par Chrome et Firefox. onload est déclenché par Internet Explorer. Edge ne déclenche ni une erreur ni une charge. Je n'utiliserais pas cette méthode mais cela pourrait fonctionner dans certains cas. Voir également

<link> onerror ne fonctionne pas dans IE

*

Définition et utilisation L'événement onerror est déclenché si une erreur survient lors du chargement d'un fichier externe (par exemple un document ou une image).

Conseil: Lorsqu'ils sont utilisés sur des supports audio / vidéo, les événements associés qui se produisent en cas de perturbation du processus de chargement des supports sont les suivants:

  • onabort
  • onemptied
  • installé
  • mise en suspension

En HTML:

element onerror = "myScript">

En JavaScript , en utilisant la méthode addEventListener ():

object.addEventListener ("erreur", myScript);

Remarque: la méthode addEventListener () n'est pas prise en charge dans Internet Explorer 8 et les versions antérieures.

Exemple Exécutez un JavaScript si une erreur se produit lors du chargement d'une image:

img src = "image.gif" onerror = "maFonction ()">


0

Il a été proposé de définir un délai d'expiration, puis de supposer une défaillance de charge après un délai d'expiration.

setTimeout(fireCustomOnerror, 4000);

Le problème avec cette approche est que l'hypothèse est fondée sur le hasard. Après l'expiration de votre délai, la demande est toujours en attente. La demande du script en attente peut se charger, même après que le programmeur a supposé que le chargement ne se produirait pas.

Si la demande pouvait être annulée, le programme pourrait attendre un certain temps, puis annuler la demande.


0

Voici comment j'ai utilisé une promesse pour détecter les erreurs de chargement qui sont émises sur l'objet window:

<script type='module'>
window.addEventListener('error', function(error) {
  let url = error.filename
  url = url.substring(0, (url.indexOf("#") == -1) ? url.length : url.indexOf("#"));
  url = url.substring(0, (url.indexOf("?") == -1) ? url.length : url.indexOf("?"));
  url = url.substring(url.lastIndexOf("/") + 1, url.length);
  window.scriptLoadReject && window.scriptLoadReject[url] && window.scriptLoadReject[url](error);
}, true);
window.boot=function boot() {
  const t=document.createElement('script');
  t.id='index.mjs';
  t.type='module';
  new Promise((resolve, reject) => {
    window.scriptLoadReject = window.scriptLoadReject || {};
    window.scriptLoadReject[t.id] = reject;
    t.addEventListener('error', reject);
    t.addEventListener('load', resolve); // Careful load is sometimes called even if errors prevent your script from running! This promise is only meant to catch errors while loading the file.
  }).catch((value) => {
    document.body.innerHTML='Error loading ' + t.id + '! Please reload this webpage.<br/>If this error persists, please try again later.<div><br/>' + t.id + ':' + value.lineno + ':' + value.colno + '<br/>' + (value && value.message);
  });
  t.src='./index.mjs'+'?'+new Date().getTime();
  document.head.appendChild(t);
};
</script>
<script nomodule>document.body.innerHTML='This website needs ES6 Modules!<br/>Please enable ES6 Modules and then reload this webpage.';</script>
</head>

<body onload="boot()" style="margin: 0;border: 0;padding: 0;text-align: center;">
  <noscript>This website needs JavaScript!<br/>Please enable JavaScript and then reload this webpage.</noscript>

0

Eh bien, la seule façon dont je peux penser à faire tout ce que vous voulez est assez moche. Exécutez d'abord un appel AJAX pour récupérer le contenu du fichier Javascript. Lorsque cela est terminé, vous pouvez vérifier le code d'état pour décider si cela a réussi ou non. Ensuite, prenez le responseText de l'objet xhr et enveloppez-le dans un try / catch, créez dynamiquement une balise de script, et pour IE, vous pouvez définir la propriété text de la balise de script sur le texte JS, dans tous les autres navigateurs, vous devriez pouvoir ajoutez un nœud de texte avec le contenu à la balise script. S'il y a un code qui s'attend à ce qu'une balise de script contienne réellement l'emplacement src du fichier, cela ne fonctionnera pas, mais cela devrait convenir dans la plupart des situations.


Cette solution est bien obsolète avec les navigateurs modernes.
Simon_Weaver
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.