Як дізнатися, чи не вдалося завантажити тег <script>


111

Я динамічно додаю <script>теги до сторінки<head> , і я хотів би мати можливість сказати, чи не вдалося завантаження якимось чином - 404, помилка сценарію у завантаженому сценарії, будь-що.

У Firefox це працює:

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

Однак це не працює в IE або Safari.

Хтось знає про спосіб зробити цю роботу в інших браузерах, крім Firefox?

(Я не думаю, що рішення, яке вимагає розміщення спеціального коду у файлах .js, є гарним. Це неелегантно і негнучко.)


4
Великий веб-сайт, автоматичне завантаження залежностей від вмісту, завантаженого через ajax. if+ опитування - це набридлива суть, яку я не хочу вкладати у всі JS.
Девід

2
Ви також можете перевірити збій завантаження під час подання запиту JSONP, використовуючи введення тегів сценарію ...
schellsan

2
Перейти до анс stackoverflow.com/questions/538745 / ...
Pacerier

Відповіді:


36

Немає події помилки для тегу сценарію. Ви можете сказати, коли він успішний, і припустити, що він не завантажився після таймауту:

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

7
Слухач "завантаження" буде звільнений, навіть якщо є помилка javascript.
Лука Маттейс

38
Ну, так, якщо файл ЗАВАНТАЖИТЬСЯ і є помилка в самому файлі, але якщо файл не подається, завантаження ніколи не запуститься.
Діод - Джеймс Макфарлан

1
так, правда, саме тому я попросив бути більш конкретним, яку саме помилку він шукає.
Лука Маттейс

1
Але час очікування повинен бути наданий кодером сторінки правильно? Таким чином, кодер може вибрати інший тайм-аут для веб-переглядача, припустимо, час завантаження сценарію вичерпано, а потім досягти успіху трохи пізніше. Чи ні?
hippietrail

6
Існує onerror evnt для тегу сценарію. Він запуститься, коли ресурс не знайдений.
Nguyen Tran

24

Якщо ви переймаєтесь лише браузерами html5, ви можете використовувати події помилок (оскільки це стосується лише помилок, слід підтримувати це лише в браузерах наступного покоління для KISS IMHO).

З специфікації:

Якщо значенням атрибуту src є порожній рядок або якщо його не вдалося вирішити, тоді користувальницький агент повинен поставити в чергу завдання, щоб запустити просту подію з іменем помилки на елементі та скасувати ці кроки.

~

Якщо завантаження призвело до помилки (наприклад, помилка DNS або помилка HTTP 404), виконання блоку сценарію повинно просто полягати в запуску простого події, названого помилкою на елементі.

Це означає, що вам не потрібно робити опитування, схильне до помилок, і ви можете комбінувати його з атрибутом async і defer, щоб переконатися, що сценарій не блокує візуалізацію сторінки:

Атрибут відстрочки може бути визначений, навіть якщо вказаний атрибут async, щоб застарілі веб-браузери, які підтримують лише відкладати (а не асинхронізувати), повернутися до поведінки відстрочки замість синхронної поведінки блокування, яка є типовою.

Детальніше про http://www.w3.org/TR/html5/scripting-1.html#script


1
Будь-яка ідея реалізації JSONP, як, наприклад, у jQuery, підтримує це? Все, що я читав тут про виявлення того, що збою JSONP завантажується, говорить про те, що його неможливо виявити, але тайм-аут може бути вирішеним, і до останньої версії JSONP було додано тайм-аут. Здається, що ця відповідь забезпечує щось краще, ніж час очікування - це правильно?
hippietrail

1
Приклад можливий, будь ласка?
rogerdpack

13
<script src="nonexistent.js" onerror="alert('error!')"></script> скрипка
Rudey

@Rudey Uncaught SyntaxError: Unexpected token '<'(в останньому Chrome)
daleyjem

@daleyjem здається, що ви намагалися поставити тег HTML у JavaScript. <script src="nonexistent.js" onerror="alert('error!')"></script>повинен містити ваш HTML-файл, а не JS.
Rudey

21

Сценарій від Erwinus працює чудово, але не дуже чітко закодований. Я взяв на себе сміливість його почистити і розшифрувати, що це робило. Я вніс ці зміни:

  • Значущі назви змінних
  • Використання prototype.
  • require() використовує змінну аргументу
  • Немає alert()повідомлень не повертаються за замовчуванням
  • Виправлені деякі синтаксичні помилки та проблеми із сферою застосування, які я отримував

Ще раз дякую Ервінусу, сама функціональність на місці.

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
Я змушений був використовувати $ .getScript jQuery , оскільки ця функція не вдалася до кешованих сценаріїв у MSIE8-, на жаль
Zathrus Writer

@ZathrusWriter це, мабуть, краща ідея, дякую, що повідомили нам! Ви, ймовірно, можете додати випадковий int до URL у цьому коді, і це видалить кешування.
Арам Кочарян

2
Так, Арам, це, безумовно, зробить трюк, однак це також призведе до скасування кешування браузера, тому накладні витрати в такому випадку, мабуть, не дуже варті;)
Zathrus Writer

@ZathrusWriter, то як працює робота з реалізацією jQuery?
Печер'є

@Pacerier Вибачте, я не розробник ядра jQuery, тому я не можу відповісти на це
Zathrus Writer

18

моє робоче чисте рішення (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);
 })

}

Як вказував Мартін, використовується так:

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

АБО

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

1
Використовуйте його наступним чином:loaderScript("myscript.js").then(() => { console.log("loaded"); }).catch(() => { console.log("error"); });
Мартін Ховеке

17

Я знаю, що це стара тема, але я отримав приємне рішення для вас (я думаю). Це скопійовано з мого класу, який обробляє всі речі AJAX.

Коли сценарій не може бути завантажений, він встановлює оброблювач помилок, але коли обробник помилок не підтримується, він повертається до таймера, який перевіряє на помилки протягом 15 секунд.

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
... звідки взявся jQuery?
Naftali aka Neal

1
А також, це крос-браузерне рішення ;-)
Codebeat

1
@Erwinus Я не перевіряв заголовки, це була лише швидка крос-браузерна перевірка, яку я виконував, і $ .getScript завжди працював без проблем, тому я затримався з цим ... ви можете спробувати себе, я використовую W7 і XAMPP тут
Zathrus Writer

19
Чи працює це чи ні, читати боляче боляче - не кажучи вже про налагодження. Це якийсь досить поганий формат та справді жорстокий стиль кодування. Сама назва змінної - безлад.
Thor84no

7
Якщо ви не бачите значення читабельного коду (і ви могли зробити його читабельним без будь-яких змін фактично виконаного коду), то мені шкода кожної людини, яка має працювати з вами та вашим кодом.
Thor84no

10

Щоб перевірити, чи nonexistant.jsне повернувся javascript без помилки, вам слід додати змінну всередині, http://fail.org/nonexistant.jsяк, var isExecuted = true;а потім перевірити, чи існує вона при завантаженні тегу сценарію.

Однак якщо ви хочете лише перевірити, що nonexistant.jsповернуто без 404 (тобто він існує), ви можете спробувати зі 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
    }
}

Це охопить обидва випадки.


1
Це працює, але насправді не робить те, що я хочу - провал у такому випадку ніколи не призведе до події. Мені не хочеться опитувати змінну, і якщо вона все-таки помиляється через кілька секунд, надішліть зворотний зворотний дзвінок.
Девід

Яку помилку ви намагаєтеся знайти? Не вдалося завантажити? Не вдалося виконати javascript у nonexstant.js? Помилка HTTP-відповіді? Будьте докладнішими.
Лука Маттейс

Будь-яке з перерахованого вище було б добре. Мені особливо важлива помилка 404.
Девід

404, тобто ви хочете перевірити, чи не існує файлу nonexistant.js? Але якщо ви хочете перевірити, чи не повернулось повідомлення про помилку?
Лука Маттейс

Привіт, Девіде, ти повинен мати можливість припустити, що якщо this.readyState / ... не відповідає дійсності, сценарій не вдалося завантажити. В основному, onError.
Коді

7

Я сподіваюсь, що це не буде усунуто, оскільки в особливих обставинах це найнадійніший спосіб вирішити проблему. Щоразу, коли сервер дозволяє отримати ресурс Javascript за допомогою CORS ( http://en.wikipedia.org/wiki/Cross-origin_resource_sharing ), у вас є багатий набір варіантів для цього.

Використання XMLHttpRequest для отримання ресурсів буде працювати у всіх сучасних браузерах, включаючи IE. Оскільки ви хочете завантажити Javascript, у вас в першу чергу доступний Javascript. Ви можете відстежувати хід за допомогою ReadyState ( http://en.wikipedia.org/wiki/XMLHttpRequest#The_onreadystatechange_event_listener ). Нарешті, як тільки ви отримаєте вміст файлу, ви можете виконати його за допомогою eval (). Так, я сказав, що eval - адже безпека не відрізняється від нормальної завантаження сценарію. Насправді, подібний прийом пропонує Джон Ресіг, щоб мати приємніші теги ( http://ejohn.org/blog/degrading-script-tags/ ).

Цей метод дозволяє також відокремити завантаження від eval та виконувати функції до та після того, як відбувається eval. Це стає дуже корисним при паралельному завантаженні скриптів, але оцінюючи їх один за одним - те, що браузери можуть зробити легко, коли розміщуєте теги в HTML, але не дозволятимуть, додаючи сценарії під час виконання Javascript.

CORS також є кращим для JSONP для завантаження скриптів ( http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests ). Однак якщо ви розробляєте власні сторонні віджети для вбудовування на інші веб-сайти, вам слід фактично завантажувати файли Javascript з вашого власного домену у свій власний iframe (знову ж таки, використовуючи AJAX)

Коротко:

  1. Спробуйте перевірити, чи можете ви завантажувати ресурс за допомогою AJAX GET

  2. Використовуйте eval після успішного завантаження

Щоб покращити його:

  1. Перевірте надсилаються заголовки кеш-керування

  2. Подивіться на інше кешування вмісту в localStorage, якщо вам потрібно

  3. Перевірте "принижуючий JavaScript" Resig для отримання більш чистого коду

  4. Перевірте Requ.js


Зверніть увагу, що для цього способу потрібно, щоб сервер початківців увімкнув CORS, що не завжди буває і керується: |
rogerdpack

5

Цей трюк спрацював для мене, хоча я визнаю, що це, мабуть, не найкращий спосіб вирішити цю проблему. Замість того щоб спробувати це, ви повинні зрозуміти, чому javascripts не завантажуються Спробуйте зберегти локальну копію сценарію на вашому сервері тощо або зверніться до постачальника третьої сторони, звідки ви намагаєтесь завантажити сценарій.

У будь-якому випадку, ось ось такий спосіб: 1) Ініціалізувати змінну в хибну; 2) Встановити її як істину, коли завантажується javascript (використовуючи атрибут onload) 3) перевірити, чи змінна правда чи помилка після завантаження тіла 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
Що робити, якщо сценарій все ще завантажується? Звідки ви знаєте, якщо файл не знайдено чи потрібно просто почекати?
оса

Це рішення працює в моєму тестуванні, доки тег сценарію розміщується безпосередньо у джерелі документа. Подія завантаження документа не спрацьовує, поки всі ресурси, на які посилається джерело сторінки, вже не завантажені (або вийшли з ладу). Якщо вам потрібно пізніше вставити скрипти в DOM, вам потрібен інший підхід.
Jamey Sharp

Прекрасне рішення. Я не розумію, чому це не було схвалено.
Лотфі

Це передбачає, що сценарій буде завантажений синхронно, блокуючи все інше, що не завжди відповідає дійсності. Насправді це не рекомендований спосіб завантаження скриптів.
Vitim.us

4

Ось ще одне рішення на основі JQuery без таймерів:

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

Дякуємо: https://stackoverflow.com/a/14691735/1243926

Використання зразка (оригінальний зразок з документації на 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>

Гарний Сергій! Отже, ви використовуєте .get (), щоб перевірити, чи існує файл, і .getScript (), щоб перевірити, чи можна його виконувати / завантажувати без помилок?
jjwdesign

2
Так. Як я пам’ятаю, у цього підходу є обмеження: ви не зможете завантажувати багато сценаріїв таким чином --- якщо я пам’ятаю правильно, через обмеження сценаріїв міждоменного сценарію.
osa

Проблема використання jQuery (або іншої бібліотеки) полягає в тому, що спочатку потрібно завантажити цю бібліотеку. Тож як перевірити, чи не вдалося завантажити цю бібліотеку?
Pacerier

Я також застосував такий підхід, але рекомендую використовувати cache:trueдля виклику $ .getScript (це вимкнено за замовчуванням). Таким чином, для більшості запитів він автоматично використовує кешовану версію для дзвінка getScript (заощаджуючи затримку)
Laurens Rietveld

2

Це можна зробити безпечно, використовуючи обіцянки

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

і використовувати так

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

Причина, що вона не працює в Safari, полягає в тому, що ви використовуєте синтаксис атрибутів. Це буде добре працювати, хоча:

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

... окрім IE.

Якщо ви хочете перевірити виконаний сценарій успішно, просто встановіть змінну за допомогою цього сценарію і перевірте, чи він встановлений у зовнішньому коді.


Це фактично не має ніякої різниці для Safari - він все ще не запускає обробник помилок.
Девід

У мене виникла проблема з обробником onclick в сафарі, і це було виправлено, тому я подумав, що це теж буде для onerror. Мабуть, ні ...

1
Чи повинно це працювати і для статично включених тегів скриптів, або лише тих, що динамічно вводяться? Я просто намагався використовувати його, щоб виявити, чи не вдалося завантажити jQuery, але це не спрацювало. Я не впевнений, чи роблю я це неправильно, чи це просто не працює в цьому випадку.
hippietrail

1
@hippietrail - слухач подій ніколи не працюватиме над статичним HTML <script>. Якщо ви спробуєте додати його раніше, ви отримаєте помилку про те, що тег не існує, а якщо ви додасте його після цього, сценарій вже запущений і викликав його події. Єдиний спосіб - це шукати побічні ефекти, спричинені сценарієм.

Завдяки флюсенції. Шкода, що це працює лише для 404, а не для JS-помилок. Встановлення змінної всередині сценарію не завжди можливо.
Джо Лісс

0

Було запропоновано встановити тайм-аут, а потім припустити збій завантаження після таймауту.

setTimeout(fireCustomOnerror, 4000);

Проблема такого підходу полягає в тому, що припущення засноване на випадковості. Після закінчення терміну очікування запит ще очікує. Запит на очікуваний сценарій може завантажитися навіть після того, як програміст припустив, що завантаження не відбудеться.

Якщо запит можна було скасувати, програма могла почекати певний період, а потім скасувати запит.


0

Ось як я використав обіцянку для виявлення помилок завантаження, які видаються на об’єкт вікна:

<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

Ну, єдиний спосіб, коли я можу думати робити все, що ти хочеш, - це досить негарно. Спочатку виконайте виклик AJAX, щоб отримати вміст файлу Javascript. Коли це завершиться, ви можете перевірити код статусу, щоб визначити, вдалося це чи ні. Потім візьміть responseText з об’єкта xhr і загортайте його в спробу / catch, динамічно створюйте тег сценарію, а для IE ви можете встановити властивість тексту тегу сценарію до тексту JS, у всіх інших браузерах ви повинні мати можливість додайте текстовий вузол із вмістом до тегу сценарію. Якщо є який-небудь код, який очікує, що тег скрипта насправді містить src-розташування файлу, це не працюватиме, але це повинно бути добре в більшості ситуацій.


Це рішення застаріло за допомогою сучасних браузерів.
Simon_Weaver

0

подія onerror

* Оновлення серпня 2017 року: onerror запускається Chrome і Firefox. onload запускається Internet Explorer. Край не спрацьовує ні помилки, ні завантаження. Я не хотів би використовувати цей метод, але він може працювати в деяких випадках. Дивитися також

<link> onerror не працює в IE

*

Визначення та використання Подія onerror викликається, якщо виникає помилка під час завантаження зовнішнього файла (наприклад, документа чи зображення).

Порада. При використанні на аудіо / відео носіях пов'язані події, які виникають, коли відбувається якесь порушення процесу завантаження носія:

  • onabort
  • однозначно
  • встановити
  • витрата

В HTML:

елемент onerror = "myScript">

У JavaScript , використовуючи метод addEventListener ():

object.addEventListener ("помилка", myScript);

Примітка. Метод addEventListener () не підтримується в Internet Explorer 8 та більш ранніх версіях.

Приклад Виконайте JavaScript, якщо виникає помилка під час завантаження зображення:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.