Jak sprawdzić, czy nie udało się załadować tagu <script>


112

Dynamicznie dodaję <script>tagi do strony <head>i chciałbym być w stanie stwierdzić, czy ładowanie się w jakiś sposób nie powiodło - 404, błąd skryptu w załadowanym skrypcie, cokolwiek.

W przeglądarce Firefox działa to:

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

Jednak to nie działa w IE lub Safari.

Czy ktoś zna sposób, aby to działało w przeglądarkach innych niż Firefox?

(Nie sądzę, aby rozwiązanie wymagające umieszczenia specjalnego kodu w plikach .js było dobre. Jest nieeleganckie i nieelastyczne).


4
Duża strona internetowa, automatyczne ładowanie zależności dla treści ładowanych przez ajax. if+ sondowanie jest denerwującym okrucieństwem, którego nie chcę umieszczać we wszystkich JS.
David

2
Możesz również chcieć sprawdzić błąd ładowania podczas wysyłania żądania JSONP za pomocą wstrzyknięcia tagu skryptu ...
schellsan

Odpowiedzi:


36

Nie ma zdarzenia błędu dla tagu skryptu. Możesz stwierdzić, kiedy się powiedzie, i założyć, że nie został załadowany po upływie limitu czasu:

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

7
Odbiornik „onload” zostanie uruchomiony, nawet jeśli wystąpi błąd javascript.
Luca Matteis

38
Cóż, tak, jeśli plik ŁADUJE się i jest błąd w samym pliku, ale jeśli plik nie jest obsługiwany, onload nigdy nie zostanie uruchomiony.
Diodeus - James MacFarlane

1
tak, to prawda, dlatego poprosiłem o dokładniejsze określenie, jakiego rodzaju błędu szuka.
Luca Matteis

1
Ale limit czasu musi być zapewniony przez programistę strony, prawda? Koder może więc wybrać inny limit czasu niż przeglądarka, założyć, że upłynął limit czasu ładowania skryptu, a następnie sprawić, że zakończy się sukcesem nieco później. Albo nie?
hippietrail

6
Istnieje jeden błąd związany z tagiem skryptu. Zostanie uruchomiony, gdy nie zostanie znaleziony zasób.
Nguyen Tran

24

Jeśli zależy Ci tylko na przeglądarkach HTML5, możesz użyć zdarzenia błędu (ponieważ służy to tylko do obsługi błędów, powinno być w porządku, aby obsługiwać to tylko w przeglądarkach następnej generacji dla KISS IMHO).

Ze specyfikacji:

Jeśli wartością atrybutu src jest pusty ciąg lub jeśli nie można go rozwiązać, agent użytkownika musi umieścić zadanie w kolejce, aby uruchomić proste zdarzenie o nazwie error w elemencie, i przerwać te kroki.

~

Jeśli ładowanie spowodowało błąd (na przykład błąd DNS lub błąd HTTP 404), wykonanie bloku skryptu musi polegać tylko na wywołaniu prostego zdarzenia o nazwie error na elemencie.

Oznacza to, że nie musisz wykonywać żadnych podatnych na błędy sondowań i możesz łączyć je z atrybutami async i defer, aby upewnić się, że skrypt nie blokuje renderowania strony:

Atrybut defer może zostać określony, nawet jeśli określono atrybut async, aby spowodować, że starsze przeglądarki sieci Web, które obsługują tylko odraczanie (a nie asynchroniczność), powracają do zachowania odroczenia zamiast do domyślnego zachowania synchronicznego blokowania.

Więcej na http://www.w3.org/TR/html5/scripting-1.html#script


1
Masz jakiś pomysł na implementacje JSONP, takie jak w jQuery, które to obsługują? Wszystko, co przeczytałem tutaj na temat wykrywania niepowodzeń ładowania JSONP, mówi, że nie można go wykryć, ale przekroczenie limitu czasu może być obejściem, a limit czasu został dodany do najnowszej wersji JSONP. Wygląda na to, że ta odpowiedź zapewnia coś lepszego niż limit czasu - czy to prawda?
hippietrail

1
przykład możliwy proszę?
rogerdpack

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

@Rudey Uncaught SyntaxError: Unexpected token '<'(w najnowszym Chrome)
daleyjem

@daleyjem brzmi tak, jakbyś próbował umieścić tag HTML w JavaScript. <script src="nonexistent.js" onerror="alert('error!')"></script>powinien znaleźć się w pliku HTML, a nie JS.
Rudey

21

Skrypt Erwinusa działa świetnie, ale nie jest zbyt jasno zakodowany. Pozwoliłem sobie wyczyścić to i rozszyfrować, co robi. Dokonałem tych zmian:

  • Znaczące nazwy zmiennych
  • Korzystanie z prototype.
  • require() używa zmiennej argumentowej
  • alert()Domyślnie żadne wiadomości nie są zwracane
  • Naprawiono niektóre błędy składniowe i problemy z zakresem

Jeszcze raz dziękujemy Erwinusowi, sama funkcjonalność jest na miejscu.

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
Byłem zmuszony użyć $ .getScript jQuery , ponieważ ta funkcja zawiodła dla skryptów buforowanych w MSIE8-, niestety
Zathrus Writer

@ZathrusWriter to prawdopodobnie lepszy pomysł, dzięki za poinformowanie nas o tym! Prawdopodobnie mógłbyś dodać losowe int do adresu URL w tym kodzie i usunąłoby to buforowanie.
Aram Kocharyan

2
Tak, Aram, to z pewnością by
załatwiło

@ZathrusWriter, więc jak działa implementacja jQuery?
Pacerier,

@Pacerier przepraszam, nie jestem głównym programistą jQuery, więc nie mogę na to odpowiedzieć
Zathrus Writer

18

moje działające czyste rozwiązanie (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);
 })

}

Jak zauważył Martin, użyte w ten sposób:

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

LUB

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

1
Użyj go w następujący sposób:loaderScript("myscript.js").then(() => { console.log("loaded"); }).catch(() => { console.log("error"); });
Martin Wantke

17

Wiem, że to stary wątek, ale mam dla ciebie fajne rozwiązanie (chyba). Jest skopiowany z mojej klasy, która obsługuje wszystkie rzeczy AJAX.

Gdy nie można załadować skryptu, ustawia procedurę obsługi błędów, ale gdy nie jest obsługiwana, powraca do licznika czasu, który sprawdza błędy przez 15 sekund.

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
... skąd się wzięło jQuery?
Naftali aka Neal

1
A także jest to rozwiązanie dla różnych przeglądarek ;-)
Codebeat

1
@Erwinus Nie sprawdzałem nagłówków, to było po prostu szybkie sprawdzenie w przeglądarce, które wykonałem i $ .getScript zawsze działał bez problemów, więc utknąłem z tym ... zapraszam do wypróbowania, używam W7 i XAMPP tutaj
Zathrus Writer,

19
Czy to działa, czy nie, czytanie jest cholernie bolesne - nie mówiąc już o debugowaniu. To całkiem kiepskie formatowanie i naprawdę okropny styl kodowania. Samo nazewnictwo zmiennych to bałagan.
Thor84no

7
Jeśli nie widzisz wartości czytelnego kodu (i możesz uczynić go czytelnym bez żadnych zmian w faktycznie wykonywanym kodzie), to żal mi każdej osoby, która musi pracować z Tobą i Twoim kodem.
Thor84no

10

Aby sprawdzić, czy javascript nonexistant.jsnie zwróciło błędu, musisz dodać zmienną wewnątrz http://fail.org/nonexistant.jslike, var isExecuted = true;a następnie sprawdzić, czy istnieje, gdy tag skryptu jest ładowany.

Jeśli jednak chcesz tylko sprawdzić, czy nonexistant.jszwrócony jest bez 404 (co oznacza, że ​​istnieje), możesz spróbować ze isLoadedzmienną ...

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

Obejmuje to oba przypadki.


1
Działa, ale tak naprawdę nie robi tego, co chcę - awaria w takim przypadku nigdy nie wywołałaby zdarzenia. Nie chcę odpytywać o zmienną i, jeśli po kilku sekundach nadal jest fałszywa, odpalić wywołanie zwrotne w przypadku awarii.
David

Jaki rodzaj błędu próbujesz odzyskać? Nie udało się załadować? Błąd wykonania javascript w nonexstant.js? Błąd odpowiedzi HTTP? Prosimy o bardziej opisowy charakter.
Luca Matteis

Każde z powyższych byłoby dobre. Szczególnie zależy mi jednak na błędzie 404.
David

404, co oznacza, że ​​chcesz sprawdzić, czy plik nonexistant.js nie istnieje? Ale jeśli chcesz sprawdzić, czy nie zwrócił żadnego błędu?
Luca Matteis

Hej David, powinieneś być w stanie założyć, że jeśli this.readyState / ... nie jest prawdziwe, to skrypt nie został załadowany. Zasadniczo onError.
Cody

7

Mam nadzieję, że nie zostanie to odrzucone, ponieważ w szczególnych okolicznościach jest to najbardziej niezawodny sposób rozwiązania problemu. Za każdym razem, gdy serwer umożliwia pobranie zasobu Javascript za pomocą CORS ( http://en.wikipedia.org/wiki/Cross-origin_resource_sharing ), masz do dyspozycji bogatą gamę opcji.

Używanie XMLHttpRequest do pobierania zasobów będzie działać we wszystkich nowoczesnych przeglądarkach, w tym IE. Ponieważ chcesz załadować Javascript, przede wszystkim masz JavaScript dostępny. Postęp możesz śledzić za pomocą readyState ( http://en.wikipedia.org/wiki/XMLHttpRequest#The_onreadystatechange_event_listener ). Wreszcie, po otrzymaniu zawartości pliku, możesz go wykonać za pomocą eval (). Tak, powiedziałem eval - ponieważ pod względem bezpieczeństwa nie różni się to od normalnego ładowania skryptu. W rzeczywistości podobną technikę sugeruje John Resig, aby mieć ładniejsze tagi ( http://ejohn.org/blog/degrading-script-tags/ ).

Ta metoda pozwala również oddzielić ładowanie od eval i wykonywać funkcje przed i po wystąpieniu eval. Staje się bardzo przydatne podczas równoległego ładowania skryptów, ale oceniając je jeden po drugim - coś, co przeglądarki mogą łatwo zrobić, gdy umieścisz tagi w HTML, ale nie pozwala na to, dodając skrypty w czasie wykonywania za pomocą JavaScript.

CORS jest również lepszy od JSONP do ładowania skryptów ( http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests ). Jeśli jednak opracowujesz własne widżety innych firm, które mają być osadzone w innych witrynach, w rzeczywistości powinieneś załadować pliki Javascript z własnej domeny do własnego elementu iframe (ponownie za pomocą AJAX)

W skrócie:

  1. Spróbuj sprawdzić, czy możesz załadować zasób za pomocą AJAX GET

  2. Użyj eval po pomyślnym załadowaniu

Aby to poprawić:

  1. Sprawdź wysyłane nagłówki kontroli pamięci podręcznej

  2. Jeśli potrzebujesz, zajrzyj do buforowania zawartości w localStorage w inny sposób

  3. Sprawdź „degradujący javascript” Resiga, aby uzyskać bardziej przejrzysty kod

  4. Sprawdź require.js


Uwaga: ten sposób wymaga, aby serwer pochodzenia miał włączony mechanizm CORS, co nie zawsze ma miejsce lub nie zawsze jest możliwe do kontrolowania: |
rogerdpack

5

Ta sztuczka mi się sprawdziła, choć przyznaję, że to chyba nie jest najlepszy sposób na rozwiązanie tego problemu. Zamiast próbować tego, powinieneś zobaczyć, dlaczego skrypty JavaScript się nie ładują. Spróbuj zachować lokalną kopię skryptu na swoim serwerze itp. Lub skontaktuj się z dostawcą zewnętrznym, z którego próbujesz pobrać skrypt.

Tak czy inaczej, więc oto obejście: 1) Zainicjuj zmienną na false 2) Ustaw ją na true, gdy ładuje się javascript (używając atrybutu onload) 3) sprawdź, czy zmienna ma wartość true lub false po załadowaniu treści HTML

<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
A jeśli skrypt nadal się ładuje? Skąd wiesz, czy plik nie został znaleziony, czy po prostu musisz poczekać?
osa

To rozwiązanie działa w moich testach, o ile tag script jest umieszczony bezpośrednio w źródle dokumentu. Zdarzenie onload dokumentu nie jest uruchamiane, dopóki wszystkie zasoby, do których odwołuje się źródło strony, nie zostaną już załadowane (lub zakończone niepowodzeniem). Jeśli jednak chcesz później wstawić skrypty do DOM, potrzebujesz innego podejścia.
Jamey Sharp

Świetne rozwiązanie. Nie rozumiem, dlaczego nie zostało to przyjęte.
Lotfi

Zakłada się, że skrypt zostanie załadowany synchronicznie, blokując wszystko inne, co nie zawsze jest prawdą. W rzeczywistości nie jest to zalecany sposób ładowania skryptów.
Vitim.us

4

Oto kolejne rozwiązanie oparte na JQuery bez żadnych timerów:

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

Dzięki: https://stackoverflow.com/a/14691735/1243926

Przykładowe użycie (oryginalna próbka z dokumentacji 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>

Miły Siergiej! Więc używasz .get (), aby sprawdzić, czy plik istnieje i .getScript (), aby sprawdzić, czy można go wykonać / załadować bez błędów?
jjwdesign

2
Tak. O ile pamiętam, to podejście ma ograniczenia: nie będziesz w stanie załadować wielu skryptów w ten sposób - o ile dobrze pamiętam, z powodu ograniczeń dotyczących skryptów międzydomenowych.
osa

Problem z korzystaniem z jQuery (lub innej biblioteki) polega na tym, że musisz najpierw załadować tę bibliotekę. Jak więc sprawdzić, czy ta biblioteka się nie załadowała?
Pacerier

Podjąłem również takie podejście, ale polecam użycie cache:truedla wywołania $ .getScript (jest to domyślnie wyłączone). W ten sposób dla większości żądań automatycznie używa wersji z pamięci podręcznej do wywołania getScript (oszczędzając opóźnienie)
Laurens Rietveld,

2

Można to zrobić bezpiecznie, korzystając z obietnic

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

i używaj w ten sposób

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

Powodem, dla którego nie działa w Safari, jest to, że używasz składni atrybutów. To jednak zadziała dobrze:

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

... z wyjątkiem IE.

Jeśli chcesz sprawdzić skrypt wykonany pomyślnie, po prostu ustaw zmienną za pomocą tego skryptu i sprawdź, czy jest ustawiona w zewnętrznym kodzie.


W rzeczywistości nie ma to żadnego znaczenia dla Safari - nadal nie uruchamia modułu obsługi błędów.
David

Miałem problem z obsługą onclick w safari i to właśnie go rozwiązało, więc pomyślałem, że to samo będzie dotyczyło onerror. Najwyraźniej nie ...

1
Czy powinno to działać również w przypadku tagów skryptów dołączanych statycznie, czy tylko tych wprowadzanych dynamicznie? Po prostu próbowałem go użyć do wykrycia, czy nie udało się załadować jQuery, ale to nie zadziałało. Nie jestem pewien, czy robię to źle, czy po prostu w tym przypadku nie działa.
hippietrail

1
@hippietrail - detektor zdarzeń nigdy nie będzie działał na statycznym kodzie HTML <script>. Jeśli spróbujesz dodać go wcześniej, pojawi się błąd, że tag nie istnieje, a jeśli dodasz go później, skrypt już się uruchomił i wyzwolił swoje zdarzenia. Jedynym sposobem jest wyszukanie skutków ubocznych spowodowanych przez skrypt.

Dzięki flussence. Szkoda, że ​​działa to tylko dla 404, a nie dla błędów JS. Ustawienie zmiennej w skrypcie nie zawsze jest wykonalne.
Jo Liss

1

zdarzenie powodujące błąd

* Aktualizacja sierpień 2017: onerror jest uruchamiany przez Chrome i Firefox. onload jest uruchamiany przez Internet Explorer. Edge nie uruchamia się ani przy błędzie, ani podczas ładowania. Nie użyłbym tej metody, ale w niektórych przypadkach może działać. Zobacz też

<link> onerror nie działa w IE

*

Definicja i zastosowanie Zdarzenie onerror jest wyzwalane, jeśli podczas ładowania pliku zewnętrznego (np. Dokumentu lub obrazu) wystąpi błąd.

Wskazówka: W przypadku użycia na mediach audio / wideo, powiązane zdarzenia, które występują, gdy występują jakieś zakłócenia w procesie ładowania multimediów, to:

  • onabort
  • onemptied
  • zainstalowany
  • onsuspend

W HTML:

element onerror = "myScript">

W JavaScript za pomocą metody addEventListener ():

object.addEventListener ("błąd", myScript);

Uwaga: metoda addEventListener () nie jest obsługiwana w programie Internet Explorer 8 i wcześniejszych wersjach.

Przykład Wykonaj JavaScript, jeśli wystąpi błąd podczas ładowania obrazu:

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


0

Zaproponowano ustawienie limitu czasu, a następnie założenie awarii ładowania po upływie limitu czasu.

setTimeout(fireCustomOnerror, 4000);

Problem z takim podejściem polega na tym, że założenie jest oparte na przypadku. Po wygaśnięciu limitu czasu żądanie nadal oczekuje. Żądanie oczekującego skryptu może zostać załadowane, nawet jeśli programista założył, że ładowanie nie nastąpi.

Jeśli żądanie można anulować, program może czekać przez pewien czas, a następnie anulować żądanie.


0

Oto jak wykorzystałem obietnicę do wykrycia błędów ładowania, które są emitowane na obiekcie 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

Cóż, jedyny sposób, w jaki mogę myśleć o robieniu wszystkiego, co chcesz, jest dość brzydki. Najpierw wykonaj wywołanie AJAX, aby pobrać zawartość pliku Javascript. Po zakończeniu możesz sprawdzić kod stanu, aby zdecydować, czy to się powiodło, czy nie. Następnie weź responseText z obiektu xhr i zawiń go w try / catch, dynamicznie utwórz tag script, a dla IE możesz ustawić właściwość text tagu script na tekst JS, we wszystkich innych przeglądarkach powinieneś być w stanie dołącz węzeł tekstowy z zawartością do tagu script. Jeśli istnieje kod, który oczekuje, że tag skryptu faktycznie zawiera lokalizację src pliku, to nie zadziała, ale powinno wystarczyć w większości sytuacji.


To rozwiązanie jest przestarzałe w nowoczesnych przeglądarkach.
Simon_Weaver,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.