How to tell if a ` [fiddle](https://jsfiddle.net/dtc16732/) – Rudey Feb 17 '17 at 10:48

  • 1
    @Rudey `Uncaught SyntaxError: Unexpected token '<'` (in latest Chrome) – daleyjem Feb 29 '20 at 05:25
  • @daleyjem sounds like you've attempted to put a HTML tag in JavaScript. `` should go in your HTML file, not JS. – Rudey Mar 03 '20 at 16:18
  • 35

    There is no error event for the script tag. You can tell when it is successful, and assume that it has not loaded after a timeout:

    <script type="text/javascript" onload="loaded=1" src="....js"></script>
    
    Diodeus - James MacFarlane
    • 112,730
    • 33
    • 157
    • 176
    • 8
      The "onload" listener will be fired even if there's a javascript error. – Luca Matteis Feb 11 '09 at 21:38
    • 44
      Well, yes if the file LOADS and there is an error in the file itself, but if the file is not served up, the onload will never fire. – Diodeus - James MacFarlane Feb 11 '09 at 21:49
    • 1
      yes, true, that's why I asked to be more specific of what kind of error he's looking for. – Luca Matteis Feb 11 '09 at 21:51
    • Ok, sorry for the downvote, seems like he's looking for both 404 error (which will work with your solution), and also javascript error, which will work with mine. – Luca Matteis Feb 11 '09 at 21:52
    • 1
      But the timeout has to be provided by the page's coder right? So the coder might choose a different timeout to the browser, assume the script load timed out, and then have it succeed a bit later. Or not? – hippietrail Dec 26 '11 at 21:18
    • I guess there is one for HTML5 now? – rogerdpack Oct 27 '16 at 20:26
    • 17
      There is onerror evnt for script tag. It will fire when the resource not found. – Nguyen Tran Dec 22 '17 at 08:59
    • 1
      Note I found I needed a combination of both the onload and onerror events. If there is a syntax error in the script (e.g. error in code, truncated source, or html error page), the onload event will fire and the onerror event will not fire. If the resource fails to be fetched (404) the onerror event will fire. In IE11 onerror also fired if escape was pressed before the file loaded (tested using fiddler and long timeout on script file in autoresponder). Here is a jsbin test: https://jsbin.com/jusoyob – robocat Nov 15 '18 at 02:43
    • 2
      @Diodeus-JamesMacFarlane as others have commented, there *is* an `error` event, at least in all modern browsers - down voted for incorrectly stating "There is no error event for the script tag". Please update or remove this outdated/wrong answer. – mindplay.dk Oct 28 '21 at 13:11
    28

    my working clean solution (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);
     })
    
    }
    

    As Martin pointed, used like that:

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

    OR

    try{
     await loaderScript("myscript.js")
     console.log("loaded"); 
    }catch{
     console.log("error");
    }
    
    Gibin Ealias
    • 2,751
    • 5
    • 21
    • 39
    pery mimon
    • 7,713
    • 6
    • 52
    • 57
    • 1
      Use it as follows: `loaderScript("myscript.js").then(() => { console.log("loaded"); }).catch(() => { console.log("error"); });` – Martin Wantke Sep 20 '17 at 17:28
    21

    The script from Erwinus works great, but isn't very clearly coded. I took the liberty to clean it up and decipher what it was doing. I've made these changes:

    • Meaningful variable names
    • Use of prototype.
    • require() uses an argument variable
    • No alert() messages are returned by default
    • Fixed some syntax errors and scope issues I was getting

    Thanks again to Erwinus, the functionality itself is spot on.

    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
    • 20,165
    • 11
    • 81
    • 96
    • 4
      I was forced to use jQuery's [$.getScript](http://api.jquery.com/jQuery.getScript/), as this function did fail for cached scripts in MSIE8-, unfortunatelly – Zathrus Writer Jun 04 '13 at 10:35
    • @ZathrusWriter that's probably a better idea, thanks for letting us know! You could probably add a random int to the url in this code and it would remove the caching. – Aram Kocharyan Jun 04 '13 at 14:23
    • 2
      Yes Aram, that would certainly do the trick, however it would also invalidate browser's caching, so the overhead in such case is probably not really worth it ;) – Zathrus Writer Jun 04 '13 at 16:14
    • @ZathrusWriter, so how does the workings of the jQuery implementation work? – Pacerier May 07 '14 at 09:02
    • @Pacerier sorry, I'm not a jQuery core developer, so I can't really answer that – Zathrus Writer May 07 '14 at 09:11
    17

    I know this is an old thread but I got a nice solution to you (I think). It's copied from an class of mine, that handles all AJAX stuff.

    When the script cannot be loaded, it set an error handler but when the error handler is not supported, it falls back to a timer that checks for errors for 15 seconds.

    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');
        });
    });
    
    Optimus
    • 1,354
    • 1
    • 21
    • 40
    Codebeat
    • 6,501
    • 6
    • 57
    • 99
    • 4
      ...where did jQuery come from? – Naftali Aug 04 '11 at 20:29
    • You are using `$('#'+os)` and one or two others. you did notstate in your answer that you are using jQuery – Naftali Aug 04 '11 at 20:50
    • 1
      And also, it is a cross-browser solution ;-) – Codebeat Aug 04 '11 at 20:50
    • https://github.com/LivePress/scriptcaller - this project does exactly this in a cross-browser way with a nice interface – gleber Jun 07 '12 at 17:48
    • @gleber: This script is also cross-browser but with one major advantage: the code is less. – Codebeat Jun 08 '12 at 19:42
    • I was forced to use jQuery's [$.getScript](http://api.jquery.com/jQuery.getScript/), as this function did fail for cached scripts in MSIE8-, unfortunatelly – Zathrus Writer Jun 04 '13 at 10:35
    • @Zathrus: Sorry to hear that. Since I wrote this, never experience any problems with it and I also use caching at serving my scripts. Did you check the http headers of your caching method are well-formed? $.getScript is not the same as inserting a link tag to the head section of the page. – Codebeat Jun 05 '13 at 01:57
    • 1
      @Erwinus I did not check headers, it was just a quick cross-browser check that I performed and *$.getScript* always ran without problems, so I stuck with it... you are welcome to try yourself, I'm using W7 and XAMPP here – Zathrus Writer Jun 05 '13 at 13:20
    • @Erwinus, Please add in which browsers are supported in the answer too, that would be helpful. – Pacerier May 07 '14 at 08:49
    • 21
      Whether this works or not, it's damned painful to read - let alone debug. That's some pretty poor formatting and truly atrocious coding style. The variable naming alone is a mess. – Vala Nov 21 '14 at 11:26
    • Thank you for your kindness, @Thor84no. I hope you enjoy it. Code is designed for SPEED. Look at the answer of Aram Kocharyan, if you want to get it clearer if you don't understand it. – Codebeat Nov 21 '14 at 18:04
    • 7
      If you don't see the value of readable code (and you could make that readable without any changes to actually executed code), then I feel sorry for every single person that has to work with you and your code. – Vala Nov 22 '14 at 23:07
    • 1
      @Thor84no: Thank you for you concerns. You are free to don't use it if you don't like it. Have a nice day. – Codebeat Nov 23 '14 at 05:24
    • This works for me, but I had to remove an extra }; on the line before o.require. Regarding its readability, I think that critics should present a better solution rather than ridicule the only solution presented. Most code that is considered well written by critics really ends up looking like hieroglyphics anyway. – Dave Oct 06 '15 at 21:28
    • @Dave Yesterday. Fixed it, thanks. Well, about the style of the code, I like it short (saves some bytes at downloading). The first letter is expected type. When you know this you don't need long var names, type is important. Because javascript is a untyped language, it's nice to know what the var must be instead of a long name that could be wrong. – Codebeat Oct 08 '15 at 10:13
    10

    To check if the javascript in nonexistant.js returned no error you have to add a variable inside http://fail.org/nonexistant.js like var isExecuted = true; and then check if it exists when the script tag is loaded.

    However if you only want to check that the nonexistant.js returned without a 404 (meaning it exists), you can try with a isLoaded variable ...

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

    This will cover both cases.

    Luca Matteis
    • 29,161
    • 19
    • 114
    • 169
    • 1
      It works, but doesn't really do what I want -- a failure in that case would never fire an event. I don't want to have to poll for a variable and, if it's still false after a few seconds, fire the on-fail callback. – David Feb 11 '09 at 21:43
    • What kind of error are you trying to retrieve? Failure to load? Failure to execute the javascript in nonexstant.js? HTTP Response Error? Please be more descriptive. – Luca Matteis Feb 11 '09 at 21:45
    • Any of the above would be good. I specifically care about a 404 error, though. – David Feb 11 '09 at 21:50
    • 404, meaning you want to check if the file nonexistant.js doesn't exist? But if it does you want to check if it returned no error? – Luca Matteis Feb 11 '09 at 21:52
    • Hey David, you should be able to assume that if this.readyState/... is not true, then the script failed to load. Basically an onError. – Cody Aug 16 '12 at 23:44
    • @Cody, he is saying the onload callback didn't even run because there is no onload event (example internet down or server down etc etc) – Pacerier Jun 21 '13 at 17:35
    7

    I hope this doesn't get downvoted, because in special circumstances it is the most reliable way to solve the problem. Any time the server allows you to get a Javascript resource using CORS (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing), you have a rich array of options to do so.

    Using XMLHttpRequest to fetch resources will work across all modern browsers, including IE. Since you are looking to load Javascript, you have Javascript available to you in the first place. You can track the progress using the readyState (http://en.wikipedia.org/wiki/XMLHttpRequest#The_onreadystatechange_event_listener). Finally, once you receive the content of the file, you can execute it with eval ( ). Yes, I said eval -- because security-wise it is no different from loading the script normally. In fact, a similar technique is suggested by John Resig to have nicer tags (http://ejohn.org/blog/degrading-script-tags/).

    This method also lets you separate the loading from the eval, and execute functions before and after the eval happens. It becomes very useful when loading scripts in parallel but evaluating them one after the other -- something browsers can do easily when you place the tags in HTML, but don't let you by adding scripts at run-time with Javascript.

    CORS is also preferable to JSONP for loading scripts (http://en.wikipedia.org/wiki/XMLHttpRequest#Cross-domain_requests). However, if you are developing your own third-party widgets to be embedded in other sites, you should actually load the Javascript files from your own domain in your own iframe (again, using AJAX)

    In short:

    1. Try to see if you can load the resource using AJAX GET

    2. Use eval after it has successfully loaded

    To improve it:

    1. Check out the cache-control headers being sent

    2. Look into otherwise caching the content in localStorage, if you need to

    3. Check out Resig's "degrading javascript" for cleaner code

    4. Check out require.js

    rogerdpack
    • 62,887
    • 36
    • 269
    • 388
    Gregory Magarshak
    • 1,883
    • 2
    • 25
    • 35
    • NB that this way requires the origin server to have CORS enabled, which is not always the case or controllable :| – rogerdpack Oct 27 '16 at 20:34
    5

    This trick worked for me, although I admit that this is probably not the best way to solve this problem. Instead of trying this, you should see why the javascripts aren't loading. Try keeping a local copy of the script in your server, etc. or check with the third party vendor from where you are trying to download the script.

    Anyways, so here's the workaround: 1) Initialize a variable to false 2) Set it to true when the javascript loads (using the onload attribute) 3) check if the variable is true or false once the HTML body has loaded

    <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
    • 244
    • 2
    • 2
    • 1
      What if the script is still loading? How do you know if the file was not found or if you just have to wait? – Sergey Orshanskiy Oct 14 '13 at 03:28
    • This solution works in my testing, as long as the script tag is placed directly in the document source. The document's onload event doesn't fire until all resources referenced in the page source have already loaded (or failed). If you need to insert scripts into the DOM later, though, you need another approach. – Jamey Sharp Nov 27 '13 at 18:29
    • Great solution. I don't understand why it hasn't been upvoted. – Lotfi Nov 11 '14 at 08:35
    • This assumes that the script will be loaded synchronously blocking everything else, which is not always true. In fact, it is not a recommended way of loading scripts. – Vitim.us Jun 25 '19 at 20:02
    4

    Here is another JQuery-based solution without any timers:

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

    Thanks to: https://stackoverflow.com/a/14691735/1243926

    Sample usage (original sample from JQuery getScript documentation):

    <!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>
    
    Community
    • 1
    • 1
    Sergey Orshanskiy
    • 6,794
    • 1
    • 46
    • 50
    • Nice Sergey! So, you're using .get() to check if the file exists and .getScript() to check to see if it can be executed/loaded without errors? – jjwdesign Nov 13 '13 at 18:24
    • 2
      Yes. As I recall, this approach does have limitations: you won't be able to load many scripts in this way --- if I remember correctly, because of cross-domain scripting restrictions. – Sergey Orshanskiy Nov 14 '13 at 00:47
    • The problem with using jQuery (or another library) is that you need to first load that library. So how do you check if *that* library failed to load? – Pacerier May 07 '14 at 09:04
    • I've taken this approach as well, but I recommend using `cache:true` for the $.getScript call (this is off by default). This way, for most requests, it automatically uses the cached version for the getScript call (saving you latency) – Laurens Rietveld Dec 10 '14 at 16:32
    4

    This can be done safely using promises

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

    and use like this

        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}`)
        );
    
    Lahiru Mirihagoda
    • 1,113
    • 1
    • 16
    • 30
    Beingnin
    • 2,288
    • 1
    • 21
    • 37
    3

    onerror Event

    *Update August 2017: onerror is fired by Chrome and Firefox. onload is fired by Internet Explorer. Edge fires neither onerror nor onload. I wouldnt use this method but it could work in some cases. See also

    <link> onerror do not work in IE

    *

    Definition and Usage The onerror event is triggered if an error occurs while loading an external file (e.g. a document or an image).

    Tip: When used on audio/video media, related events that occurs when there is some kind of disturbance to the media loading process, are:

    • onabort
    • onemptied
    • onstalled
    • onsuspend

    In HTML:

    element onerror="myScript">

    In JavaScript, using the addEventListener() method:

    object.addEventListener("error", myScript);

    Note: The addEventListener() method is not supported in Internet Explorer 8 and earlier versions.

    Example Execute a JavaScript if an error occurs when loading an image:

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

    1

    The reason it doesn't work in Safari is because you're using attribute syntax. This will work fine though:

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

    ...except in IE.

    If you want to check the script executed successfully, just set a variable using that script and check for it being set in the outer code.

    • That actually doesn't make any difference for Safari -- it still doesn't fire the error handler. – David Feb 11 '09 at 21:35
    • I had a problem with an onclick handler in safari and this was what fixed it, so I thought it'd be the same for onerror too. Apparently not... –  Feb 11 '09 at 21:53
    • 1
      Should this work for statically included script tags too, or just ones injected dynamically? I just tried to use it to detect if jQuery failed to load but it didn't work. I'm not sure if I'm doing it wrong or it just doesn't work in this case. – hippietrail Dec 26 '11 at 21:50
    • 1
      @hippietrail - an event listener will never work on a static HTML ` –  Jan 01 '12 at 03:12
    • Thanks flussence. Too bad that this only works for 404, not for JS errors. Setting a variable inside the script is not always practicable. – Jo Liss Mar 23 '12 at 17:06
    1

    This doesn't need jquery, doesn't need to load the script async, needs no timer nor to have the loaded script set a value. I've tested it in FF, Chrome, and Safari.

    <script>
            function loadScript(src) {
              return new Promise(function(resolve, reject) {
    
                let s = window.document.createElement("SCRIPT");
    
                s.onload = () => resolve(s);
                s.onerror = () => reject(new Error(src));
                s.src = src;
                // don't bounce to global handler on 404.
                s.addEventListener('error', function() {});
                window.document.head.append(s);
              }); 
            }   
                            
            let successCallback = (result) => {
              console.log(scriptUrl + " loaded.");
            }   
                            
            let failureCallback = (error) => {
              console.log("load failed: " + error.message);
            }   
                            
            loadScript(scriptUrl).then(successCallback, failureCallback);
    </script>
    
    Alan Wendt
    • 17
    • 3
    0

    It was proposed to set a timeout and then assume load failure after a timeout.

    setTimeout(fireCustomOnerror, 4000);
    

    The problem with that approach is that the assumption is based on chance. After your timeout expires, the request is still pending. The request for the pending script may load, even after the programmer assumed that load won't happen.

    If the request could be canceled, then the program could wait for a period, then cancel the request.

    sth
    • 222,467
    • 53
    • 283
    • 367
    Garrett
    • 2,936
    • 1
    • 20
    • 22
    0

    Well, the only way I can think of doing everything you want is pretty ugly. First perform an AJAX call to retrieve the Javascript file contents. When this completes you can check the status code to decide if this was successful or not. Then take the responseText from the xhr object and wrap it in a try/catch, dynamically create a script tag, and for IE you can set the text property of the script tag to the JS text, in all other browsers you should be able to append a text node with the contents to script tag. If there's any code that expects a script tag to actually contain the src location of the file, this won't work, but it should be fine for most situations.

    Bhargav Rao
    • 50,140
    • 28
    • 121
    • 140
    nickjsify
    • 39
    • 7
    0

    This is how I used a promise to detect loading errors that are emited on the window object:

    <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
    • 146
    • 2
    • 3