Làm thế nào để biết thẻ <script> không tải được


111

Tôi đang thêm động <script>các thẻ vào một trang <head>và tôi muốn biết liệu tải không thành công theo một cách nào đó - lỗi 404, lỗi tập lệnh trong tập lệnh được tải, bất cứ điều gì.

Trong Firefox, điều này hoạt động:

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

Tuy nhiên, điều này không hoạt động trong IE hoặc Safari.

Có ai biết cách làm cho tính năng này hoạt động trên các trình duyệt khác ngoài Firefox không?

(Tôi không nghĩ rằng một giải pháp yêu cầu đặt mã đặc biệt trong các tệp .js là một giải pháp tốt. Nó không phù hợp và không linh hoạt.)


4
Trang web lớn, tự động tải các phụ thuộc cho nội dung được tải thông qua ajax. if+ thăm dò ý kiến ​​là một vấn đề khó chịu mà tôi không muốn phải đưa vào tất cả JS.
David

2
Bạn cũng có thể muốn kiểm tra cho sự thất bại tải khi thực hiện một yêu cầu JSONP sử dụng tiêm script tag ...
schellsan

Câu trả lời:


36

Không có sự kiện lỗi nào cho thẻ script. Bạn có thể biết khi nào nó thành công và giả sử rằng nó chưa tải sau một khoảng thời gian chờ:

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

7
Trình nghe "onload" sẽ được kích hoạt ngay cả khi có lỗi javascript.
Luca Matteis

38
Vâng, có nếu tệp LOADS và có lỗi trong chính tệp, nhưng nếu tệp không được cung cấp, tệp tải lên sẽ không bao giờ kích hoạt.
Diodeus - James MacFarlane 11/02/09

1
vâng, đúng, đó là lý do tại sao tôi yêu cầu cụ thể hơn về loại lỗi mà anh ấy đang tìm kiếm.
Luca Matteis 11/02/09

1
Nhưng thời gian chờ phải được cung cấp bởi coder của trang phải không? Vì vậy, người viết mã có thể chọn thời gian chờ khác cho trình duyệt, giả sử quá thời gian tải tập lệnh và sau đó sẽ thành công một chút sau đó. Hay không?
hippietrail

6
Có một lỗi gợi ý cho thẻ script. Nó sẽ kích hoạt khi không tìm thấy tài nguyên.
Nguyen Tran

24

Nếu bạn chỉ quan tâm đến trình duyệt html5, bạn có thể sử dụng sự kiện lỗi (vì điều này chỉ để xử lý lỗi, nên chỉ hỗ trợ điều này trên các trình duyệt thế hệ tiếp theo cho KISS IMHO).

Từ thông số kỹ thuật:

Nếu giá trị của thuộc tính src là chuỗi trống hoặc nếu nó không thể được giải quyết, thì tác nhân người dùng phải xếp hàng một tác vụ để kích hoạt một sự kiện đơn giản có tên là lỗi tại phần tử và hủy bỏ các bước này.

~

Nếu quá trình tải dẫn đến lỗi (ví dụ: lỗi DNS hoặc lỗi HTTP 404) Việc thực thi khối tập lệnh chỉ bao gồm việc kích hoạt một sự kiện đơn giản có tên là lỗi tại phần tử.

Điều này có nghĩa là bạn không phải thực hiện bất kỳ cuộc thăm dò nào dễ xảy ra lỗi và có thể kết hợp nó với thuộc tính async và defer để đảm bảo rằng tập lệnh không chặn hiển thị trang:

Thuộc tính defer có thể được chỉ định ngay cả khi thuộc tính async được chỉ định, để làm cho các trình duyệt Web kế thừa chỉ hỗ trợ defer (chứ không phải async) quay trở lại hành vi trì hoãn thay vì hành vi chặn đồng bộ như mặc định.

Thêm trên http://www.w3.org/TR/html5/scripting-1.html#script


1
Bất kỳ ý tưởng nào về triển khai JSONP, như vậy trong jQuery có hỗ trợ điều này không? Mọi thứ tôi đã đọc ở đây về việc phát hiện JSONP không tải được cho biết không thể phát hiện được nhưng thời gian chờ có thể là một giải pháp thay thế và thời gian chờ đã được thêm vào phiên bản JSONP gần đây. Có vẻ như câu trả lời này cung cấp một cái gì đó tốt hơn so với thời gian chờ - điều đó có chính xác không?
hippietrail

1
xin vui lòng cho ví dụ có thể?
rogerdpack

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

@Rudey Uncaught SyntaxError: Unexpected token '<'(trong Chrome mới nhất)
daleyjem

@daleyjem có vẻ như bạn đã cố gắng đặt một thẻ HTML vào JavaScript. <script src="nonexistent.js" onerror="alert('error!')"></script>sẽ đi trong tệp HTML của bạn, không phải JS.
Rudey

21

Tập lệnh của Erwinus hoạt động tốt, nhưng không được mã hóa rõ ràng. Tôi có quyền tự do dọn dẹp nó và giải mã những gì nó đang làm. Tôi đã thực hiện những thay đổi này:

  • Tên biến có ý nghĩa
  • Sử dụng prototype.
  • require() sử dụng một biến đối số
  • Không có alert()tin nhắn nào được trả lại theo mặc định
  • Đã sửa một số lỗi cú pháp và các vấn đề về phạm vi mà tôi gặp phải

Cảm ơn Erwinus một lần nữa, bản thân chức năng đã được phát huy.

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
Tôi đã buộc phải sử dụng $ .getScript của jQuery , vì chức năng này không thành công đối với các tập lệnh được lưu trong bộ nhớ cache trong MSIE8-, tiếc là
Zathrus Writer

@ZathrusWriter đó có lẽ là một ý tưởng hay hơn, cảm ơn bạn đã cho chúng tôi biết! Bạn có thể thêm một int ngẫu nhiên vào url trong mã này và nó sẽ xóa bộ nhớ đệm.
Aram Kocharyan

2
Đúng vậy Aram, điều đó chắc chắn sẽ làm được thủ thuật, tuy nhiên nó cũng sẽ làm mất hiệu lực bộ nhớ đệm của trình duyệt, vì vậy chi phí trong trường hợp như vậy có lẽ không thực sự đáng giá;)
Zathrus Writer

@ZathrusWriter, vậy hoạt động của việc triển khai jQuery hoạt động như thế nào?
Pacerier

@Pacerier xin lỗi, tôi không phải là nhà phát triển cốt lõi của jQuery, vì vậy tôi thực sự không thể trả lời điều đó
Zathrus Writer

18

giải pháp sạch làm việc của tôi (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);
 })

}

Như Martin đã chỉ ra, được sử dụng như thế:

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

HOẶC LÀ

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

1
Sử dụng nó như sau:loaderScript("myscript.js").then(() => { console.log("loaded"); }).catch(() => { console.log("error"); });
Martin Wantke

17

Tôi biết đây là một chủ đề cũ nhưng tôi có một giải pháp tốt cho bạn (tôi nghĩ). Nó được sao chép từ một lớp của tôi, xử lý tất cả những thứ AJAX.

Khi không thể tải tập lệnh, nó sẽ đặt một trình xử lý lỗi nhưng khi trình xử lý lỗi không được hỗ trợ, nó sẽ quay trở lại bộ hẹn giờ kiểm tra lỗi trong 15 giây.

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 đến từ đâu?
Naftali aka Neal

1
Ngoài ra, nó là một giải pháp trình duyệt chéo ;-)
Codebeat

1
@Erwinus Tôi đã không kiểm tra tiêu đề, đó chỉ là kiểm tra nhanh trên nhiều trình duyệt mà tôi đã thực hiện và $ .getScript luôn chạy mà không có vấn đề gì, vì vậy tôi bị mắc kẹt với nó ... bạn có thể tự mình thử, tôi đang sử dụng W7 và XAMPP ở đây
Zathrus Writer

19
Cho dù điều này có hiệu quả hay không, thì thật là đau đớn khi đọc - hãy để một mình gỡ lỗi. Đó là một số định dạng khá kém và phong cách mã hóa thực sự tàn bạo. Chỉ riêng việc đặt tên biến đã là một mớ hỗn độn.
Thor84no,

7
Nếu bạn không thấy giá trị của mã có thể đọc được (và bạn có thể làm cho mã đó có thể đọc được mà không có bất kỳ thay đổi nào đối với mã thực sự được thực thi), thì tôi cảm thấy tiếc cho mọi người phải làm việc với bạn và mã của bạn.
Thor84no

10

Để kiểm tra xem javascript được nonexistant.jstrả về không bị lỗi hay không, bạn phải thêm một biến bên trong http://fail.org/nonexistant.jslike var isExecuted = true;và sau đó kiểm tra xem nó có tồn tại khi thẻ script được tải hay không.

Tuy nhiên, nếu bạn chỉ muốn kiểm tra xem giá trị nonexistant.jstrả về mà không có 404 (nghĩa là nó tồn tại), bạn có thể thử với một isLoadedbiến ...

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

Điều này sẽ bao gồm cả hai trường hợp.


1
Nó hoạt động, nhưng không thực sự làm những gì tôi muốn - một thất bại trong trường hợp đó sẽ không bao giờ dẫn đến một sự kiện. Tôi không muốn phải thăm dò ý kiến ​​cho một biến và nếu nó vẫn sai sau vài giây, hãy kích hoạt lệnh gọi lại không thành công.
David

Bạn đang cố gắng truy xuất loại lỗi nào? Không tải được? Không thể thực thi javascript trong nonexstant.js? Lỗi phản hồi HTTP? Vui lòng mô tả nhiều hơn.
Luca Matteis

Bất kỳ điều nào ở trên sẽ tốt. Tuy nhiên, tôi đặc biệt quan tâm đến lỗi 404.
David

404, nghĩa là bạn muốn kiểm tra xem tệp nonexistant.js có tồn tại không? Nhưng nếu bạn muốn kiểm tra xem nó có trả về lỗi không?
Luca Matteis 11/02/09

Này David, bạn có thể giả định rằng nếu this.readyState / ... không đúng, thì tập lệnh không tải được. Về cơ bản là một lỗi onError.
Cody

7

Tôi hy vọng điều này không bị phản đối vì trong những trường hợp đặc biệt, đó là cách đáng tin cậy nhất để giải quyết vấn đề. Bất cứ lúc nào máy chủ cho phép bạn lấy tài nguyên Javascript bằng CORS ( http://en.wikipedia.org/wiki/Cross-origin_resource_sharing ), bạn có một loạt các tùy chọn để làm như vậy.

Sử dụng XMLHttpRequest để tìm nạp tài nguyên sẽ hoạt động trên tất cả các trình duyệt hiện đại, bao gồm cả IE. Vì bạn đang tìm cách tải Javascript, nên ngay từ đầu bạn đã có sẵn Javascript. Bạn có thể theo dõi tiến trình bằng readyState ( http://en.wikipedia.org/wiki/XMLHttpRequest#The_onreadystatechange_event_listener ). Cuối cùng, khi bạn nhận được nội dung của tệp, bạn có thể thực thi nó với eval (). Vâng, tôi đã nói là eval - bởi vì về mặt bảo mật, nó không khác gì tải tập lệnh bình thường. Trên thực tế, một kỹ thuật tương tự được John Resig đề xuất để có các thẻ đẹp hơn ( http://ejohn.org/blog/degrading-script-tags/ ).

Phương pháp này cũng cho phép bạn tách việc tải khỏi eval và thực thi các hàm trước và sau khi eval xảy ra. Nó trở nên rất hữu ích khi tải các tập lệnh song song nhưng đánh giá chúng lần lượt - điều mà các trình duyệt có thể thực hiện dễ dàng khi bạn đặt các thẻ trong HTML, nhưng không cho phép bạn thêm các tập lệnh vào lúc chạy bằng Javascript.

CORS cũng thích hợp hơn JSONP để tải các tập lệnh ( http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests ). Tuy nhiên, nếu bạn đang phát triển các tiện ích của bên thứ ba của riêng mình để được nhúng vào các trang web khác, bạn thực sự nên tải các tệp Javascript từ miền của riêng bạn trong iframe của riêng bạn (một lần nữa, sử dụng AJAX)

Nói ngắn gọn:

  1. Hãy thử xem bạn có thể tải tài nguyên bằng AJAX GET không

  2. Sử dụng eval sau khi tải thành công

Để cải thiện nó:

  1. Kiểm tra các tiêu đề kiểm soát bộ nhớ cache đang được gửi

  2. Xem xét cách khác vào bộ nhớ đệm nội dung trong localStorage, nếu bạn cần

  3. Kiểm tra "javascript giảm chất lượng" của Resig để biết mã sạch hơn

  4. Kiểm tra request.js


NB rằng theo cách này yêu cầu máy chủ gốc phải bật CORS, điều này không phải lúc nào cũng vậy hoặc có thể kiểm soát được: |
rogerdpack

5

Thủ thuật này đã hiệu quả với tôi, mặc dù tôi thừa nhận rằng đây có lẽ không phải là cách tốt nhất để giải quyết vấn đề này. Thay vì thử điều này, bạn nên xem tại sao javascrip không tải. Hãy thử giữ một bản sao cục bộ của tập lệnh trong máy chủ của bạn, v.v. hoặc kiểm tra với nhà cung cấp bên thứ ba từ nơi bạn đang cố gắng tải xuống tập lệnh.

Dù sao, vì vậy đây là cách giải quyết: 1) Khởi tạo một biến thành false 2) Đặt nó thành true khi javascript tải (sử dụng thuộc tính onload) 3) kiểm tra xem biến đó là true hay false khi nội dung HTML đã tải xong

<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
Điều gì sẽ xảy ra nếu tập lệnh vẫn đang tải? Làm thế nào để bạn biết nếu tệp không được tìm thấy hoặc nếu bạn chỉ phải đợi?
osa

Giải pháp này hoạt động trong thử nghiệm của tôi, miễn là thẻ script được đặt trực tiếp trong nguồn tài liệu. Sự kiện onload của tài liệu không kích hoạt cho đến khi tất cả các tài nguyên được tham chiếu trong nguồn trang đã được tải (hoặc không thành công). Tuy nhiên, nếu bạn cần chèn tập lệnh vào DOM sau này, bạn cần một cách tiếp cận khác.
Jamey Sharp

Giải pháp tuyệt vời. Tôi không hiểu tại sao nó không được ủng hộ.
Lotfi

Điều này giả định rằng tập lệnh sẽ được tải đồng bộ chặn mọi thứ khác, điều này không phải lúc nào cũng đúng. Trên thực tế, đó không phải là cách tải script được khuyến khích.
Vitim.us

4

Đây là một giải pháp dựa trên JQuery khác mà không cần bất kỳ bộ hẹn giờ nào:

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

Cảm ơn: https://stackoverflow.com/a/14691735/1243926

Cách sử dụng mẫu (mẫu gốc từ tài liệu 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>

Sergey đẹp! Vì vậy, bạn đang sử dụng .get () để kiểm tra xem tệp có tồn tại hay không và .getScript () để kiểm tra xem nó có thể được thực thi / tải mà không bị lỗi hay không?
jjwdesign

2
Đúng. Như tôi nhớ lại, cách tiếp cận này có những hạn chế: bạn sẽ không thể tải nhiều tập lệnh theo cách này --- nếu tôi nhớ không nhầm, vì các hạn chế về tập lệnh miền chéo.
osa

Vấn đề với việc sử dụng jQuery (hoặc một thư viện khác) là trước tiên bạn cần tải thư viện đó. Vậy làm cách nào để kiểm tra xem thư viện đó không tải được hay không?
Pacerier

Tôi cũng đã thực hiện cách tiếp cận này, nhưng tôi khuyên bạn nên sử dụng cache:truecho lệnh gọi $ .getScript (tùy chọn này bị tắt theo mặc định). Bằng cách này, đối với hầu hết các yêu cầu, nó sẽ tự động sử dụng các phiên bản cache cho cuộc gọi getScript (giúp bạn tiết kiệm thời gian trễ)
Laurens Rietveld

2

Điều này có thể được thực hiện một cách an toàn bằng cách sử dụng các lời hứa

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

và sử dụng như thế này

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

Lý do nó không hoạt động trong Safari là vì bạn đang sử dụng cú pháp thuộc tính. Điều này sẽ hoạt động tốt mặc dù:

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

... ngoại trừ trong IE.

Nếu bạn muốn kiểm tra tập lệnh được thực thi thành công, chỉ cần đặt một biến bằng cách sử dụng tập lệnh đó và kiểm tra xem nó có được đặt trong mã bên ngoài hay không.


Điều đó thực sự không tạo ra bất kỳ sự khác biệt nào đối với Safari - nó vẫn không kích hoạt trình xử lý lỗi.
David

Tôi đã gặp sự cố với trình xử lý onclick trong safari và đây là thứ đã khắc phục sự cố, vì vậy tôi nghĩ lỗi này cũng vậy. Rõ ràng là không ...

1
Điều này có nên làm việc cho các thẻ tập lệnh được bao gồm tĩnh hay chỉ những thẻ được chèn động? Tôi chỉ cố gắng sử dụng nó để phát hiện xem jQuery không tải được nhưng nó không hoạt động. Tôi không chắc liệu mình có đang làm sai hay nó không hoạt động trong trường hợp này.
hippietrail

1
@hippietrail - trình xử lý sự kiện sẽ không bao giờ hoạt động trên HTML tĩnh <script>. Nếu bạn cố gắng thêm nó trước đó thì bạn sẽ gặp lỗi rằng thẻ không tồn tại và nếu bạn thêm nó sau đó thì tập lệnh đã chạy và kích hoạt các sự kiện của nó. Cách duy nhất là tìm kiếm các tác dụng phụ do kịch bản gây ra.

Cảm ơn flussence. Thật tệ là điều này chỉ hoạt động cho 404, không cho lỗi JS. Đặt một biến bên trong script không phải lúc nào cũng khả thi.
Jo Liss

0

Nó được đề xuất để đặt thời gian chờ và sau đó giả định tải không thành công sau thời gian chờ.

setTimeout(fireCustomOnerror, 4000);

Vấn đề với cách tiếp cận đó là giả định dựa trên cơ hội. Sau khi hết thời gian chờ của bạn, yêu cầu vẫn đang chờ xử lý. Yêu cầu cho tập lệnh đang chờ xử lý có thể tải, ngay cả sau khi lập trình viên cho rằng quá trình tải sẽ không xảy ra.

Nếu yêu cầu có thể bị hủy, thì chương trình có thể đợi một khoảng thời gian, sau đó hủy yêu cầu.


0

Đây là cách tôi sử dụng một lời hứa để phát hiện lỗi tải được tạo trên đối tượng cửa sổ:

<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

Chà, cách duy nhất tôi có thể nghĩ để làm mọi thứ bạn muốn là khá xấu xí. Đầu tiên thực hiện một lệnh gọi AJAX để lấy nội dung tệp Javascript. Khi quá trình này hoàn tất, bạn có thể kiểm tra mã trạng thái để quyết định xem việc này có thành công hay không. Sau đó, lấy responseText từ đối tượng xhr và bọc nó trong try / catch, tạo động một thẻ script và đối với IE, bạn có thể đặt thuộc tính văn bản của thẻ script thành văn bản JS, trong tất cả các trình duyệt khác, bạn có thể nối một nút văn bản với nội dung vào thẻ script. Nếu có bất kỳ mã nào yêu cầu thẻ script thực sự chứa vị trí src của tệp, điều này sẽ không hoạt động, nhưng nó sẽ ổn trong hầu hết các trường hợp.


Giải pháp này đã lỗi thời với các trình duyệt hiện đại.
Simon_Weaver

0

sự kiện onerror

* Cập nhật tháng 8 năm 2017: lỗi do Chrome và Firefox kích hoạt. onload được kích hoạt bởi Internet Explorer. Edge không bắn lỗi cũng không tải. Tôi sẽ không sử dụng phương pháp này nhưng nó có thể hoạt động trong một số trường hợp. Xem thêm

<link> onerror không hoạt động trong IE

*

Định nghĩa và Cách sử dụng Sự kiện onerror được kích hoạt nếu lỗi xảy ra khi tải tệp bên ngoài (ví dụ: tài liệu hoặc hình ảnh).

Mẹo: Khi được sử dụng trên phương tiện âm thanh / video, các sự kiện liên quan xảy ra khi có một số loại xáo trộn đối với quá trình tải phương tiện, là:

  • onabort
  • có giấy tờ
  • đã cài đặt
  • phụ thuộc vào

Trong HTML:

phần tử onerror = "myScript">

Trong JavaScript , sử dụng phương thức addEventListener ():

object.addEventListener ("error", myScript);

Lưu ý: Phương thức addEventListener () không được hỗ trợ trong Internet Explorer 8 và các phiên bản cũ hơn.

Ví dụ Thực thi JavaScript nếu có lỗi xảy ra khi tải hình ảnh:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.