7

I want to detect if a script tag (that was dynamically created and added to the DOM) fails to load. The onerror event works, except with file:// URLs in Firefox.

Unfortunately none of the techniques described here (except timeouts, which are unacceptable in my case) seem to work in Firefox if the src of the script tag is a file:// URL (or relative URL and the page was loaded via a file:// URL)

Test case:

var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', 'doesnotexist.js');
script.onerror = function() { alert("Loading failed!"); }
document.getElementsByTagName('head')[0].appendChild(script);

Load this in an HTML page with a file:// URL. The onerror event won't execute in Firefox. Load from a webserver, or on Safari or Chrome, and it will.

This seems like a bug to me. Is there any known way around it?

Community
  • 1
  • 1
tlrobinson
  • 2,812
  • 1
  • 33
  • 35
  • 7
    You should accept answers to your questions. – SLaks Nov 11 '10 at 00:33
  • @Marcel Korpel: He said that timeouts are not an option, so that won't work. – PleaseStand Nov 11 '10 at 01:30
  • 2
    For reference, the issue with Firefox not firing an `error` event when a `file://`-based URL fails to load is [Bugzilla bug 621276](http://bugzilla.mozilla.org/show_bug.cgi?id=621276). – Doug Paul Aug 01 '12 at 17:22

2 Answers2

2
var loadScript = function(scriptURL, failureCallback) {
    var script = document.createElement('script'),
        scriptProtocol = scriptURL.match(/^([a-zA-Z]+:)\/\//);
    script.setAttribute('type', 'text/javascript');

    if (navigator.product === 'Gecko' &&
        navigator.userAgent.indexOf('KHTML') === -1 &&
        window.location.protocol === 'file:' &&
        (!scriptProtocol || scriptProtocol[1] === 'file:')) {

        var req = new XMLHttpRequest();
        req.open('GET', scriptURL, true);
        req.onreadystatechange = function () {
            if (req.readyState === 4) {
                if (req.status === 0)
                    script.textContent = req.responseText;
                else
                    failureCallback();
            }
        };
        try {
            req.send(null);
        }
        catch (e) {
            failureCallback();
        }
    }
    else {
        script.setAttribute('src', scriptURL);
        script.onerror = failureCallback; 
    }

    document.getElementsByTagName('head')[0].appendChild(script);
};

loadScript('doesnotexist.js', function() { alert('Loading failed!'); });

Bit of a hack, but it seems to work.

Paul Baumgart
  • 397
  • 1
  • 7
  • As Tom points out, a drawback of this method is that you lose debugging metadata for the script if it gets loaded via XHR. – Paul Baumgart Nov 12 '10 at 00:19
1

What if you used Pauls solution to retrieve the document but ignored the result. If it loads the create your script tag. The downside is the file would load twice.