Bagaimana cara mengetahui jika tag <script> gagal dimuat

112

Saya secara dinamis menambahkan <script>tag ke halaman <head>, dan saya ingin mengetahui apakah pemuatan gagal dalam beberapa cara - 404, kesalahan skrip dalam skrip yang dimuat, apa pun.

Di Firefox, ini berfungsi:

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

Namun, ini tidak berfungsi di IE atau Safari.

Adakah yang tahu cara untuk membuat ini berfungsi di browser selain Firefox?

(Menurut saya solusi yang tidak memerlukan penempatan kode khusus dalam file .js adalah solusi yang bagus. Ini tidak elegan dan tidak fleksibel.)

David
sumber
4
Situs web besar, pemuatan otomatis ketergantungan untuk konten yang dimuat melalui ajax. if+ polling adalah hal yang menjengkelkan yang tidak ingin saya masukkan ke semua JS.
David
2
Anda mungkin juga ingin memeriksa kegagalan pemuatan saat membuat permintaan JSONP menggunakan injeksi tag skrip ...
schellsan
2
Lewati ke ans stackoverflow.com/questions/538745/…
Pacerier

Jawaban:

36

Tidak ada peristiwa kesalahan untuk tag skrip. Anda dapat mengetahui kapan itu berhasil, dan berasumsi bahwa itu belum dimuat setelah waktu tunggu:

<script type="text/javascript" onload="loaded=1" src="....js"></script>
Diodeus - James MacFarlane
sumber
7
Listener "onload" akan diaktifkan meskipun ada kesalahan javascript.
Luca Matteis
38
Ya, jika file BEBAN dan ada kesalahan di file itu sendiri, tetapi jika file tidak disajikan, onload tidak akan pernah menyala.
Diodeus - James MacFarlane
1
ya, benar, itu sebabnya saya meminta untuk lebih spesifik tentang jenis kesalahan yang dia cari.
Luca Matteis
1
Tetapi batas waktu harus disediakan oleh pembuat kode halaman, bukan? Jadi pembuat kode mungkin memilih waktu tunggu yang berbeda untuk browser, menganggap waktu pemuatan skrip telah habis, dan kemudian membuatnya berhasil sedikit kemudian. Atau tidak?
hippietrail
6
Ada evnt onerror untuk tag script. Ini akan diaktifkan ketika sumber daya tidak ditemukan.
Nguyen Tran
24

Jika Anda hanya peduli dengan browser html5 Anda dapat menggunakan peristiwa kesalahan (karena ini hanya untuk penanganan kesalahan, sebaiknya hanya mendukung ini di browser generasi berikutnya untuk KISS IMHO).

Dari spesifikasi:

Jika nilai atribut src adalah string kosong atau jika tidak dapat diselesaikan, maka agen pengguna harus memasukkan tugas ke antrean untuk mengaktifkan peristiwa sederhana bernama kesalahan pada elemen tersebut, dan membatalkan langkah-langkah ini.

~

Jika pemuatan menghasilkan kesalahan (misalnya kesalahan DNS, atau kesalahan HTTP 404) Menjalankan blok skrip harus terdiri dari penembakan peristiwa sederhana bernama kesalahan pada elemen.

Ini berarti Anda tidak perlu melakukan polling yang rawan error dan dapat menggabungkannya dengan atribut async dan defer untuk memastikan skrip tidak memblokir rendering halaman:

Atribut defer dapat ditentukan bahkan jika atribut async ditentukan, untuk menyebabkan browser Web lama yang hanya mendukung defer (dan bukan async) untuk kembali ke perilaku defer alih-alih perilaku pemblokiran sinkron yang merupakan default.

Selengkapnya tentang http://www.w3.org/TR/html5/scripting-1.html#script

andrerom
sumber
1
Ada gagasan tentang implementasi JSONP, seperti itu di jQuery mendukung ini? Semua yang saya baca di sini tentang mendeteksi bahwa JSONP gagal memuat mengatakan bahwa itu tidak dapat dideteksi tetapi waktu tunggu dapat menjadi solusi, dan batas waktu ditambahkan ke versi JSONP terbaru. Tampaknya jawaban ini memberikan sesuatu yang lebih baik daripada batas waktu - apakah itu benar?
hippietrail
1
contoh mungkin tolong?
rogerdpack
13
<script src="nonexistent.js" onerror="alert('error!')"></script> biola
Rudey
@ Rudey Uncaught SyntaxError: Unexpected token '<'(di Chrome terbaru)
daleyjem
@daleyjem sepertinya Anda mencoba memasang tag HTML di JavaScript. <script src="nonexistent.js" onerror="alert('error!')"></script>harus masuk ke file HTML Anda, bukan JS.
Rudey
21

Skrip dari Erwinus berfungsi dengan baik, tetapi tidak dikodekan dengan sangat jelas. Saya mengambil kebebasan untuk membersihkannya dan menguraikan apa yang dilakukannya. Saya telah membuat perubahan ini:

  • Nama variabel yang berarti
  • Penggunaan prototype.
  • require() menggunakan variabel argumen
  • Tidak ada alert()pesan yang dikembalikan secara default
  • Memperbaiki beberapa kesalahan sintaks dan masalah cakupan yang saya dapatkan

Terima kasih sekali lagi kepada Erwinus, fungsinya sendiri sangat tepat.

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
sumber
4
Saya terpaksa menggunakan $ .getScript jQuery , karena fungsi ini gagal untuk skrip yang di-cache di MSIE8-, sayangnya
Zathrus Writer
@ZathrusWriter itu mungkin ide yang lebih baik, terima kasih telah memberi tahu kami! Anda mungkin bisa menambahkan int acak ke url dalam kode ini dan itu akan menghapus caching.
Aram Kocharyan
2
Ya Aram, itu pasti akan berhasil, namun itu juga akan membatalkan cache browser, jadi overhead dalam kasus seperti itu mungkin tidak terlalu berharga;)
Penulis Zathrus
@ ZathrusWriter, jadi bagaimana cara kerja implementasi jQuery?
Pacerier
@Pacerier maaf, saya bukan pengembang inti jQuery, jadi saya tidak dapat menjawabnya
Zathrus Writer
18

solusi bersih kerja saya (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);
 })

}

Seperti yang Martin tunjukkan, digunakan seperti itu:

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

ATAU

try{
 await loaderScript("myscript.js")
 console.log("loaded"); 
}catch{
 console.log("error");
}
pery mimon
sumber
1
Gunakan sebagai berikut:loaderScript("myscript.js").then(() => { console.log("loaded"); }).catch(() => { console.log("error"); });
Martin Wantke
17

Saya tahu ini adalah utas lama tetapi saya punya solusi yang bagus untuk Anda (menurut saya). Ini disalin dari kelas saya, yang menangani semua hal AJAX.

Ketika skrip tidak dapat dimuat, itu mengatur penangan kesalahan tetapi ketika penangan kesalahan tidak didukung, itu kembali ke pengatur waktu yang memeriksa kesalahan selama 15 detik.

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
sumber
4
... darimana jQuery berasal?
Naftali aka Neal
1
Dan juga, ini adalah solusi lintas-browser ;-)
Codebeat
1
@Erwinus Saya tidak memeriksa header, itu hanya pemeriksaan lintas-browser cepat yang saya lakukan dan $ .getScript selalu berjalan tanpa masalah, jadi saya tetap menggunakannya ... Anda dipersilakan untuk mencoba sendiri, saya menggunakan W7 dan XAMPP di sini
Penulis Zathrus
19
Apakah ini berhasil atau tidak, sangat menyakitkan untuk dibaca - apalagi melakukan debug. Itu adalah format yang sangat buruk dan gaya pengkodean yang benar-benar mengerikan. Penamaan variabel saja sudah berantakan.
Thor84no
7
Jika Anda tidak melihat nilai dari kode yang dapat dibaca (dan Anda dapat membuatnya dapat dibaca tanpa perubahan apa pun pada kode yang benar-benar dieksekusi), maka saya merasa kasihan kepada setiap orang yang harus bekerja dengan Anda dan kode Anda.
Thor84no
10

Untuk memeriksa apakah javascript yang nonexistant.jsdikembalikan tidak ada kesalahan, Anda harus menambahkan variabel di dalam http://fail.org/nonexistant.jslike var isExecuted = true;dan kemudian memeriksa apakah ada saat tag skrip dimuat.

Namun jika Anda hanya ingin memeriksa bahwa yang nonexistant.jsdikembalikan tanpa 404 (artinya ada), Anda dapat mencoba dengan isLoadedvariabel ...

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

Ini akan mencakup kedua kasus tersebut.

Luca Matteis
sumber
1
Ini berfungsi, tetapi tidak benar-benar melakukan apa yang saya inginkan - kegagalan dalam hal itu tidak akan pernah memicu peristiwa. Saya tidak ingin melakukan polling untuk variabel dan, jika masih salah setelah beberapa detik, aktifkan callback saat gagal.
David
Jenis kesalahan apa yang Anda coba dapatkan kembali? Gagal memuat? Gagal menjalankan javascript di nonexstant.js? Kesalahan Respons HTTP? Harap lebih deskriptif.
Luca Matteis
Semua hal di atas akan bagus. Saya secara khusus peduli dengan kesalahan 404.
David
404, artinya Anda ingin memeriksa apakah file nonexistant.js tidak ada? Tetapi apakah Anda ingin memeriksa apakah itu mengembalikan tidak ada kesalahan?
Luca Matteis
Hai David, Anda harus dapat berasumsi bahwa jika this.readyState / ... tidak benar, maka skrip gagal dimuat. Pada dasarnya sebuah onError.
Cody
7

Saya harap ini tidak diturunkan suara, karena dalam keadaan khusus ini adalah cara paling andal untuk menyelesaikan masalah. Kapan pun server mengizinkan Anda untuk mendapatkan sumber daya Javascript menggunakan CORS ( http://en.wikipedia.org/wiki/Cross-origin_resource_sharing ), Anda memiliki beragam opsi untuk melakukannya.

Menggunakan XMLHttpRequest untuk mengambil sumber daya akan berfungsi di semua browser modern, termasuk IE. Karena Anda ingin memuat Javascript, Anda memiliki Javascript yang tersedia untuk Anda sejak awal. Anda dapat melacak kemajuan menggunakan readyState ( http://en.wikipedia.org/wiki/XMLHttpRequest#The_onreadystatechange_event_listener ). Terakhir, setelah Anda menerima konten file, Anda dapat menjalankannya dengan eval (). Ya, saya katakan eval - karena dari segi keamanan tidak ada bedanya dengan memuat skrip secara normal. Faktanya, teknik serupa disarankan oleh John Resig untuk memiliki tag yang lebih bagus ( http://ejohn.org/blog/degrading-script-tags/ ).

Metode ini juga memungkinkan Anda memisahkan pemuatan dari eval, dan menjalankan fungsi sebelum dan sesudah eval terjadi. Ini menjadi sangat berguna saat memuat skrip secara paralel tetapi mengevaluasinya satu demi satu - sesuatu yang dapat dilakukan browser dengan mudah saat Anda menempatkan tag di HTML, tetapi jangan biarkan Anda dengan menambahkan skrip pada waktu proses dengan Javascript.

CORS juga lebih disukai daripada JSONP untuk memuat skrip ( http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests ). Namun, jika Anda mengembangkan widget pihak ketiga Anda sendiri untuk disematkan di situs lain, Anda seharusnya memuat file Javascript dari domain Anda sendiri di iframe Anda sendiri (sekali lagi, menggunakan AJAX)

Pendeknya:

  1. Coba lihat apakah Anda dapat memuat sumber daya menggunakan AJAX GET

  2. Gunakan eval setelah berhasil dimuat

Untuk memperbaikinya:

  1. Lihat header kontrol-cache yang sedang dikirim

  2. Periksa jika tidak, caching konten di localStorage, jika Anda perlu

  3. Lihat "menurunkan javascript" Resig untuk kode yang lebih bersih

  4. Lihat require.js

Gregory Magarshak
sumber
NB dengan cara ini mengharuskan server asal untuk mengaktifkan CORS, yang tidak selalu kasus atau dapat dikontrol: |
rogerdpack
5

Trik ini berhasil untuk saya, meskipun saya akui bahwa ini mungkin bukan cara terbaik untuk menyelesaikan masalah ini. Alih-alih mencoba ini, Anda harus melihat mengapa javascript tidak dimuat. Coba simpan salinan lokal skrip di server Anda, dll. Atau tanyakan kepada vendor pihak ketiga tempat Anda mencoba mengunduh skrip.

Jadi, inilah solusinya: 1) Inisialisasi variabel ke false 2) Setel ke true saat javascript dimuat (menggunakan atribut onload) 3) periksa apakah variabel benar atau salah setelah badan HTML dimuat

<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
sumber
1
Bagaimana jika skrip masih dimuat? Bagaimana Anda tahu jika file tidak ditemukan atau Anda hanya harus menunggu?
osa
Solusi ini berfungsi dalam pengujian saya, selama tag skrip ditempatkan langsung di sumber dokumen. Peristiwa pemuatan dokumen tidak diaktifkan hingga semua sumber daya yang dirujuk di sumber halaman telah dimuat (atau gagal). Namun, jika Anda perlu memasukkan skrip ke DOM nanti, Anda memerlukan pendekatan lain.
Jamey Sharp
Solusi bagus. Saya tidak mengerti mengapa itu belum diberi suara positif.
Lotfi
Ini mengasumsikan bahwa skrip akan dimuat secara sinkron, memblokir semua yang lain, yang tidak selalu benar. Faktanya, ini bukan cara yang disarankan untuk memuat skrip.
Vitim.us
4

Berikut adalah solusi berbasis JQuery lain tanpa timer:

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

Terima kasih kepada: https://stackoverflow.com/a/14691735/1243926

Contoh penggunaan (contoh asli dari dokumentasi getScript JQuery ):

<!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
sumber
Baik Sergey! Jadi, Anda menggunakan .get () untuk memeriksa apakah file tersebut ada dan .getScript () untuk memeriksa apakah dapat dijalankan / dimuat tanpa kesalahan?
jjwdesign
2
Iya. Seingat saya, pendekatan ini memang memiliki batasan: Anda tidak akan dapat memuat banyak skrip dengan cara ini --- jika saya ingat dengan benar, karena pembatasan skrip lintas domain.
osa
Masalah dengan menggunakan jQuery (atau pustaka lain) adalah Anda harus memuat pustaka itu terlebih dahulu. Jadi bagaimana Anda memeriksa apakah yang perpustakaan gagal beban?
Pacerier
Saya telah mengambil pendekatan ini juga, tetapi saya merekomendasikan penggunaan cache:trueuntuk panggilan $ .getScript (ini dinonaktifkan secara default). Dengan cara ini, untuk sebagian besar permintaan, secara otomatis menggunakan versi cache untuk panggilan getScript (menghemat latensi Anda)
Laurens Rietveld
2

Ini dapat dilakukan dengan aman menggunakan promise

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

dan gunakan seperti ini

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

Alasan tidak berfungsi di Safari adalah karena Anda menggunakan sintaks atribut. Ini akan bekerja dengan baik:

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

... kecuali di IE.

Jika Anda ingin memeriksa skrip berhasil dieksekusi, cukup setel variabel menggunakan skrip itu dan periksa apakah sudah disetel di kode luar.


sumber
Itu sebenarnya tidak membuat perbedaan apa pun untuk Safari - masih tidak mengaktifkan penangan kesalahan.
David
Saya mengalami masalah dengan pengendali onclick di safari dan inilah yang memperbaikinya, jadi saya pikir itu juga akan sama untuk satu kesalahan. Rupanya tidak ...
1
Haruskah ini juga berfungsi untuk tag skrip yang disertakan secara statis, atau hanya yang dimasukkan secara dinamis? Saya hanya mencoba menggunakannya untuk mendeteksi jika jQuery gagal dimuat tetapi tidak berhasil. Saya tidak yakin apakah saya salah melakukannya atau tidak berhasil dalam kasus ini.
hippietrail
1
@hippietrail - pendengar acara tidak akan pernah bekerja pada HTML statis <script>. Jika Anda mencoba menambahkannya sebelumnya, Anda mendapatkan pesan kesalahan bahwa tag tidak ada, dan jika Anda menambahkannya setelahnya maka skrip sudah berjalan dan memicu kejadiannya. Satu-satunya cara adalah mencari efek samping yang disebabkan oleh skrip.
Terima kasih flussence. Sayang sekali ini hanya berfungsi untuk 404, bukan untuk kesalahan JS. Menetapkan variabel di dalam skrip tidak selalu praktis.
Jo Liss
1

Acara onerror

* Perbarui Agustus 2017: onerror diaktifkan oleh Chrome dan Firefox. onload dipicu oleh Internet Explorer. Edge tidak mengaktifkan onerror maupun onload. Saya tidak akan menggunakan metode ini tetapi dapat berhasil dalam beberapa kasus. Lihat juga

<link> onerror tidak berfungsi di IE

*

Definisi dan Penggunaan Acara onerror dipicu jika terjadi kesalahan saat memuat file eksternal (mis. Dokumen atau gambar).

Tip: Saat digunakan pada media audio / video, kejadian terkait yang terjadi ketika ada gangguan pada proses pemuatan media, adalah:

  • onabort
  • satu kali dikosongkan
  • terpasang
  • onsuspend

Dalam HTML:

elemen onerror = "myScript">

Di JavaScript , menggunakan metode addEventListener ():

object.addEventListener ("error", myScript);

Catatan: Metode addEventListener () tidak didukung di Internet Explorer 8 dan versi sebelumnya.

Contoh Jalankan JavaScript jika terjadi kesalahan saat memuat gambar:

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

William Monahan
sumber
0

Diusulkan untuk menetapkan batas waktu dan kemudian mengasumsikan kegagalan pemuatan setelah batas waktu.

setTimeout(fireCustomOnerror, 4000);

Masalah dengan pendekatan itu adalah bahwa asumsi tersebut didasarkan pada kebetulan. Setelah waktu tunggu Anda kedaluwarsa, permintaan masih menunggu keputusan. Permintaan untuk skrip yang tertunda dapat dimuat, bahkan setelah programmer berasumsi bahwa pemuatan tidak akan terjadi.

Jika permintaan bisa dibatalkan, maka program bisa menunggu beberapa saat, lalu membatalkan permintaan tersebut.

Garrett
sumber
0

Beginilah cara saya menggunakan janji untuk mendeteksi kesalahan pemuatan yang dipancarkan pada objek jendela:

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

Nah, satu-satunya cara yang bisa saya pikirkan untuk melakukan semua yang Anda inginkan sangat buruk. Pertama lakukan panggilan AJAX untuk mengambil konten file Javascript. Ketika ini selesai, Anda dapat memeriksa kode status untuk memutuskan apakah ini berhasil atau tidak. Kemudian ambil responseText dari objek xhr dan bungkus dalam try / catch, buat tag skrip secara dinamis, dan untuk IE Anda dapat mengatur properti teks dari tag skrip ke teks JS, di semua browser lain Anda seharusnya dapat melakukannya menambahkan node teks dengan konten ke tag script. Jika ada kode yang mengharapkan tag skrip untuk benar-benar berisi lokasi src dari file tersebut, ini tidak akan berfungsi, tetapi seharusnya baik-baik saja untuk sebagian besar situasi.

nickjsify
sumber
Solusi ini sudah usang dengan browser modern.
Simon_Weaver