Como saber se uma tag <script> falhou ao carregar

112

Estou adicionando <script>tags dinamicamente a uma página <head>e gostaria de poder dizer se o carregamento falhou de alguma forma - um 404, um erro de script no script carregado, qualquer coisa.

No Firefox, isso 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);

No entanto, isso não funciona no IE ou Safari.

Alguém conhece uma maneira de fazer isso funcionar em outros navegadores além do Firefox?

(Não acho que uma solução que exija a colocação de um código especial nos arquivos .js seja boa. É deselegante e inflexível.)

David
fonte
4
Grande site, carregamento automático de dependências para conteúdo carregado através de ajax. if+ polling é algo irritante que não quero colocar em todo o JS.
David
2
Você também pode querer verificar se há falha de carregamento ao fazer uma solicitação JSONP usando injeção de tag de script ...
schellsan
2
Pule para ans stackoverflow.com/questions/538745/…
Pacerier

Respostas:

36

Não há evento de erro para a tag do script. Você pode dizer quando foi bem-sucedido e supor que não foi carregado após um tempo limite:

<script type="text/javascript" onload="loaded=1" src="....js"></script>
Diodeus - James MacFarlane
fonte
7
O listener "onload" será disparado mesmo se houver um erro de javascript.
Luca Matteis
38
Bem, sim, se o arquivo CARREGAR e houver um erro no próprio arquivo, mas se o arquivo não for servido, o onload nunca será acionado.
Diodeus - James MacFarlane
1
sim, é verdade, é por isso que pedi para ser mais específico sobre que tipo de erro ele está procurando.
Luca Matteis
1
Mas o timeout tem que ser fornecido pelo codificador da página, certo? Portanto, o codificador pode escolher um tempo limite diferente para o navegador, assumir que o carregamento do script expirou e, em seguida, ter sucesso um pouco mais tarde. Ou não?
hippietrail
6
Existe onerror evnt para tag de script. Ele será acionado quando o recurso não for encontrado.
Nguyen Tran
24

Se você se preocupa apenas com os navegadores html5, pode usar o evento de erro (uma vez que é apenas para tratamento de erros, deve estar tudo bem em apenas suportar isso nos navegadores de próxima geração para KISS IMHO).

Da especificação:

Se o valor do atributo src for a string vazia ou se não puder ser resolvido, o agente do usuário deve enfileirar uma tarefa para disparar um evento simples denominado erro no elemento e abortar essas etapas.

~

Se a carga resultou em um erro (por exemplo, um erro DNS ou um erro HTTP 404), a execução do bloco de script deve consistir apenas em disparar um evento simples denominado erro no elemento.

Isso significa que você não precisa fazer nenhuma pesquisa sujeita a erros e pode combiná-la com o atributo async e defer para garantir que o script não esteja bloqueando a renderização da página:

O atributo defer pode ser especificado mesmo se o atributo async for especificado, para fazer com que os navegadores da Web legados que apenas suportam o adiamento (e não async) retornem ao comportamento defer em vez do comportamento de bloqueio síncrono que é o padrão.

Mais em http://www.w3.org/TR/html5/scripting-1.html#script

andrerom
fonte
1
Alguma ideia de implementações JSONP, como aquela em jQuery suportam isso? Tudo o que li aqui sobre a detecção de falhas de carregamento do JSONP diz que ele não pode ser detectado, mas um tempo limite pode ser uma solução alternativa e um tempo limite foi adicionado a uma versão recente do JSONP. Parece que essa resposta fornece algo melhor do que o tempo limite - correto?
hippietrail
1
exemplo possível, por favor?
rogerdpack de
13
<script src="nonexistent.js" onerror="alert('error!')"></script> violino
Rudey
@Rudey Uncaught SyntaxError: Unexpected token '<'(no Chrome mais recente)
daleyjem
@daleyjem parece que você tentou colocar uma tag HTML em JavaScript. <script src="nonexistent.js" onerror="alert('error!')"></script>deve ir em seu arquivo HTML, não JS.
Rudey
21

O script de Erwinus funciona muito bem, mas não está codificado de forma clara. Tomei a liberdade de limpar e decifrar o que estava acontecendo. Fiz estas mudanças:

  • Nomes de variáveis ​​significativas
  • Uso de prototype.
  • require() usa uma variável de argumento
  • Nenhuma alert()mensagem é retornada por padrão
  • Corrigidos alguns erros de sintaxe e problemas de escopo que eu estava recebendo

Graças novamente a Erwinus, a funcionalidade em si está no local.

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');
        }
    });
});
Aram Kocharyan
fonte
4
Fui forçado a usar $ .getScript do jQuery , pois essa função falhou para scripts em cache no MSIE8-, infelizmente
Zathrus Writer
@ZathrusWriter é provavelmente uma ideia melhor, obrigado por nos avisar! Você provavelmente poderia adicionar um int aleatório ao url neste código e isso removeria o cache.
Aram Kocharyan
2
Sim, Aram, isso certamente resolveria, no entanto, também invalidaria o cache do navegador, então a sobrecarga nesse caso provavelmente não vale a pena;)
Escritor Zathrus
@ZathrusWriter, então como funciona o funcionamento da implementação do jQuery?
Pacerier
@Pacerier, desculpe, não sou um desenvolvedor de núcleo jQuery, então não posso responder isso
Escritor Zathrus
18

minha solução de trabalho limpa (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);
 })

}

Como Martin apontou, usado assim:

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");
}
Pery Mimon
fonte
1
Use-o da seguinte maneira:loaderScript("myscript.js").then(() => { console.log("loaded"); }).catch(() => { console.log("error"); });
Martin Wantke de
17

Eu sei que este é um tópico antigo, mas eu tenho uma boa solução para você (eu acho). É copiado de uma classe minha, que lida com todas as coisas AJAX.

Quando o script não pode ser carregado, ele define um manipulador de erros, mas quando o manipulador de erros não é suportado, ele recorre a um cronômetro que verifica se há erros por 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');
    });
});
Codebeat
fonte
4
... de onde veio o jQuery?
Naftali, também conhecido como Neal
1
E também, é uma solução para vários navegadores ;-)
Codebeat
1
@Erwinus Eu não verifiquei os cabeçalhos, foi apenas uma rápida verificação cross-browser que realizei e $ .getScript sempre rodou sem problemas, então continuei ... você pode tentar, estou usando W7 e XAMPP aqui
Escritor Zathrus
19
Funcionando ou não, é doloroso de ler - quanto mais de depurar. Essa é uma formatação muito pobre e um estilo de codificação verdadeiramente atroz. A nomenclatura de variáveis ​​sozinha é uma bagunça.
Thor84no
7
Se você não vê o valor do código legível (e você poderia torná-lo legível sem nenhuma alteração no código realmente executado), sinto muito por cada pessoa que precisa trabalhar com você e seu código.
Thor84no
10

Para verificar se o javascript nonexistant.jsnão retornou nenhum erro você deve adicionar uma variável dentro do http://fail.org/nonexistant.jslike var isExecuted = true;e então verificar se ela existe quando a tag do script é carregada.

No entanto, se você deseja apenas verificar se o nonexistant.jsretornou sem um 404 (o que significa que existe), você pode tentar com uma isLoadedvariável ...

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

Isso cobrirá os dois casos.

Luca Matteis
fonte
1
Funciona, mas não faz realmente o que eu quero - uma falha, nesse caso, nunca dispararia um evento. Não quero ter que pesquisar uma variável e, se ainda for falsa após alguns segundos, acionar o retorno de chamada em caso de falha.
David
Que tipo de erro você está tentando recuperar? Falha ao carregar? Falha ao executar o javascript em nonexstant.js? Erro de resposta HTTP? Por favor, seja mais descritivo.
Luca Matteis
Qualquer uma das opções acima seria boa. No entanto, eu me preocupo especificamente com um erro 404.
David
404, o que significa que você deseja verificar se o arquivo nonexistant.js não existe? Mas se deseja verificar se não retornou nenhum erro?
Luca Matteis
Ei David, você deve ser capaz de assumir que se this.readyState / ... não for verdadeiro, o script falhou ao carregar. Basicamente, um onError.
Cody de
7

Espero que isso não seja rejeitado, porque em circunstâncias especiais é a forma mais confiável de resolver o problema. Sempre que o servidor permitir que você obtenha um recurso Javascript usando CORS ( http://en.wikipedia.org/wiki/Cross-origin_resource_sharing ), você tem uma ampla gama de opções para fazer isso.

Usar XMLHttpRequest para buscar recursos funcionará em todos os navegadores modernos, incluindo o IE. Já que você está procurando carregar o Javascript, você tem o Javascript disponível para você em primeiro lugar. Você pode acompanhar o progresso usando o readyState ( http://en.wikipedia.org/wiki/XMLHttpRequest#The_onreadystatechange_event_listener ). Finalmente, depois de receber o conteúdo do arquivo, você pode executá-lo com eval (). Sim, eu disse eval - porque em termos de segurança não é diferente de carregar o script normalmente. Na verdade, uma técnica semelhante é sugerida por John Resig para ter tags mais agradáveis ​​( http://ejohn.org/blog/degrading-script-tags/ ).

Este método também permite separar o carregamento do eval e executar funções antes e depois de o eval acontecer. Torna-se muito útil ao carregar scripts em paralelo, mas avaliando-os um após o outro - algo que os navegadores podem fazer facilmente quando você coloca as tags em HTML, mas não permitem adicionar scripts em tempo de execução com Javascript.

CORS também é preferível a JSONP para carregar scripts ( http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests ). No entanto, se você estiver desenvolvendo seus próprios widgets de terceiros para serem incorporados em outros sites, você deve realmente carregar os arquivos Javascript de seu próprio domínio em seu próprio iframe (novamente, usando AJAX)

Em resumo:

  1. Tente ver se você pode carregar o recurso usando AJAX GET

  2. Use eval após carregar com sucesso

Para melhorar:

  1. Verifique os cabeçalhos de controle de cache que estão sendo enviados

  2. Procure, de outra forma, armazenar em cache o conteúdo em localStorage, se precisar

  3. Verifique o "degrading javascript" de Resig para obter um código mais limpo

  4. Confira require.js

Gregory Magarshak
fonte
Nota que desta forma requer que o servidor de origem tenha CORS habilitado, o que nem sempre é o caso ou controlável: |
rogerdpack de
5

Esse truque funcionou para mim, embora eu admita que essa provavelmente não seja a melhor maneira de resolver o problema. Em vez de tentar isso, você deve ver porque os javascripts não estão carregando. Tente manter uma cópia local do script em seu servidor, etc. ou verifique com o fornecedor terceirizado de onde você está tentando fazer o download do script.

De qualquer forma, esta é a solução alternativa: 1) Inicialize uma variável como falsa 2) Defina como verdadeira quando o javascript carregar (usando o atributo onload) 3) verifique se a variável é verdadeira ou falsa quando o corpo do HTML for carregado

<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>
Gautam Tandon
fonte
1
E se o script ainda estiver carregando? Como saber se o arquivo não foi encontrado ou se é só esperar?
osa
Esta solução funciona em meus testes, desde que a tag do script seja colocada diretamente na origem do documento. O evento onload do documento não dispara até que todos os recursos referenciados na origem da página já tenham sido carregados (ou falhou). Se você precisar inserir scripts no DOM posteriormente, porém, precisará de outra abordagem.
Jamey Sharp
Ótima solução. Não entendo por que não foi votado.
Lotfi
Isso pressupõe que o script será carregado de forma síncrona, bloqueando todo o resto, o que nem sempre é verdade. Na verdade, não é uma maneira recomendada de carregar scripts.
Vitim.us
4

Aqui está outra solução baseada em JQuery sem nenhum temporizador:

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

Agradecimentos a: https://stackoverflow.com/a/14691735/1243926

Amostra de uso (amostra original da documentação 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>
Osa
fonte
Nice Sergey! Então, você está usando .get () para verificar se o arquivo existe e .getScript () para verificar se ele pode ser executado / carregado sem erros?
jjwdesign
2
Sim. Pelo que me lembro, essa abordagem tem limitações: você não será capaz de carregar muitos scripts dessa maneira - se bem me lembro, por causa das restrições de script entre domínios.
osa
O problema de usar jQuery (ou outra biblioteca) é que você precisa primeiro carregar essa biblioteca. Então, como você verifica se a biblioteca falhou ao carregar?
Pacerier
Também cache:trueadotei essa abordagem, mas recomendo usar para a chamada $ .getScript (desativada por padrão). Desta forma, para a maioria das solicitações, ele usa automaticamente a versão em cache para a chamada getScript (economizando latência)
Laurens Rietveld
2

Isso pode ser feito com segurança usando promessas

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

e usar assim

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}`)
);
Nithin Chandran
fonte
1

O motivo pelo qual não funciona no Safari é porque você está usando a sintaxe de atributos. Isso vai funcionar bem:

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

... exceto no IE.

Se você quiser verificar se o script foi executado com sucesso, apenas defina uma variável usando esse script e verifique se ela está definida no código externo.


fonte
Na verdade, isso não faz nenhuma diferença para o Safari - ele ainda não aciona o manipulador de erros.
David
Tive um problema com um manipulador onclick no safari e foi isso que o corrigiu, então pensei que seria o mesmo para onerror também. Aparentemente não ...
1
Isso deve funcionar também para tags de script incluídas estaticamente ou apenas aquelas injetadas dinamicamente? Eu apenas tentei usá-lo para detectar se o jQuery falhou ao carregar, mas não funcionou. Não tenho certeza se estou fazendo errado ou simplesmente não funciona neste caso.
hippietrail
1
@hippietrail - um ouvinte de evento nunca funcionará em um HTML estático <script>. Se você tentar adicioná-lo antes, receberá um erro informando que a tag não existe e, se adicioná-lo depois, o script já foi executado e acionou seus eventos. A única maneira é procurar os efeitos colaterais causados ​​pelo script.
Obrigado flussence. Uma pena que isso só funcione para 404, não para erros JS. Definir uma variável dentro do script nem sempre é praticável.
Jo Liss
1

evento onerror

* Atualização de agosto de 2017: onerror é acionado pelo Chrome e Firefox. onload é acionado pelo Internet Explorer. Edge não dispara onerror nem onload. Eu não usaria esse método, mas pode funcionar em alguns casos. Veja também

<link> onerror não funciona no IE

*

Definição e uso O evento onerror é acionado se ocorrer um erro ao carregar um arquivo externo (por exemplo, um documento ou uma imagem).

Dica: Quando usado em mídia de áudio / vídeo, os eventos relacionados que ocorrem quando há algum tipo de perturbação no processo de carregamento de mídia são:

  • Onabort
  • esvaziado
  • montado
  • suspender

Em HTML:

elemento onerror = "myScript">

Em JavaScript , usando o método addEventListener ():

object.addEventListener ("erro", myScript);

Observação: o método addEventListener () não é compatível com o Internet Explorer 8 e versões anteriores.

Exemplo: Execute um JavaScript se ocorrer um erro ao carregar uma imagem:

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

William Monahan
fonte
0

Foi proposto definir um tempo limite e, em seguida, assumir a falha de carga após um tempo limite.

setTimeout(fireCustomOnerror, 4000);

O problema com essa abordagem é que a suposição se baseia no acaso. Depois que o tempo limite expirar, a solicitação ainda estará pendente. A solicitação do script pendente pode carregar, mesmo depois que o programador presumiu que o carregamento não acontecerá.

Se a solicitação pudesse ser cancelada, o programa poderia aguardar um período e, em seguida, cancelar a solicitação.

Garrett
fonte
0

Foi assim que usei uma promessa para detectar erros de carregamento que são emitidos no objeto janela:

<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>
Mi G
fonte
0

Bem, a única maneira que consigo pensar em fazer tudo o que você quer é muito feia. Primeiro execute uma chamada AJAX para recuperar o conteúdo do arquivo Javascript. Quando isso for concluído, você pode verificar o código de status para decidir se foi bem-sucedido ou não. Em seguida, pegue o responseText do objeto xhr e envolva-o em um try / catch, crie dinamicamente uma tag de script e para o IE você pode definir a propriedade text da tag de script para o texto JS, em todos os outros navegadores você deve ser capaz de acrescente um nó de texto com o conteúdo da tag de script. Se houver algum código que espera que uma tag de script realmente contenha a localização src do arquivo, isso não funcionará, mas deve funcionar na maioria das situações.

nickjsify
fonte
Esta solução está obsoleta com os navegadores modernos.
Simon_Weaver