Dynamically load a JavaScript file

后端 未结 28 3000
说谎
说谎 2020-11-22 06:56

How can you reliably and dynamically load a JavaScript file? This will can be used to implement a module or component that when \'initialized\' the component will dynamical

相关标签:
28条回答
  • 2020-11-22 07:24

    Here a simple example for a function to load JS files. Relevant points:

    • you don't need jQuery, so you may use this initially to load also the jQuery.js file
    • it is async with callback
    • it ensures it loads only once, as it keeps an enclosure with the record of loaded urls, thus avoiding usage of network
    • contrary to jQuery $.ajax or $.getScript you can use nonces, solving thus issues with CSP unsafe-inline. Just use the property script.nonce
    var getScriptOnce = function() {
    
        var scriptArray = []; //array of urls (closure)
    
        //function to defer loading of script
        return function (url, callback){
            //the array doesn't have such url
            if (scriptArray.indexOf(url) === -1){
    
                var script=document.createElement('script');
                script.src=url;
                var head=document.getElementsByTagName('head')[0],
                    done=false;
    
                script.onload=script.onreadystatechange = function(){
                    if ( !done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') ) {
                        done=true;
                        if (typeof callback === 'function') {
                            callback();
                        }
                        script.onload = script.onreadystatechange = null;
                        head.removeChild(script);
    
                        scriptArray.push(url);
                    }
                };
    
                head.appendChild(script);
            }
        };
    }();
    

    Now you use it simply by

    getScriptOnce("url_of_your_JS_file.js");
    
    0 讨论(0)
  • 2020-11-22 07:25

    You may write dynamic script tags (using Prototype):

    new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"});
    

    The problem here is that we do not know when the external script file is fully loaded.

    We often want our dependant code on the very next line and like to write something like:

    if (iNeedSomeMore) {
        Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod();
        myFancyMethod(); // cool, no need for callbacks!
    }
    

    There is a smart way to inject script dependencies without the need of callbacks. You simply have to pull the script via a synchronous AJAX request and eval the script on global level.

    If you use Prototype the Script.load method looks like this:

    var Script = {
        _loadedScripts: [],
        include: function(script) {
            // include script only once
            if (this._loadedScripts.include(script)) {
                return false;
            }
            // request file synchronous
            var code = new Ajax.Request(script, {
                asynchronous: false,
                method: "GET",
                evalJS: false,
                evalJSON: false
            }).transport.responseText;
            // eval code on global level
            if (Prototype.Browser.IE) {
                window.execScript(code);
            } else if (Prototype.Browser.WebKit) {
                $$("head").first().insert(Object.extend(
                    new Element("script", {
                        type: "text/javascript"
                    }), {
                        text: code
                    }
                ));
            } else {
                window.eval(code);
            }
            // remember included script
            this._loadedScripts.push(script);
        }
    };
    
    0 讨论(0)
  • 2020-11-22 07:25

    There is no import / include / require in javascript, but there are two main ways to achieve what you want:

    1 - You can load it with an AJAX call then use eval.

    This is the most straightforward way but it's limited to your domain because of the Javascript safety settings, and using eval is opening the door to bugs and hacks.

    2 - Add a script tag with the script URL in the HTML.

    Definitely the best way to go. You can load the script even from a foreign server, and it's clean as you use the browser parser to evaluate the code. You can put the tag in the head of the web page, or at the bottom of the body.

    Both of these solutions are discussed and illustrated here.

    Now, there is a big issue you must know about. Doing that implies that you remotely load the code. Modern web browsers will load the file and keep executing your current script because they load everything asynchronously to improve performances.

    It means that if you use these tricks directly, you won't be able to use your newly loaded code the next line after you asked it to be loaded, because it will be still loading.

    E.G : my_lovely_script.js contains MySuperObject

    var js = document.createElement("script");
    
    js.type = "text/javascript";
    js.src = jsFilePath;
    
    document.body.appendChild(js);
    
    var s = new MySuperObject();
    
    Error : MySuperObject is undefined
    

    Then you reload the page hitting F5. And it works! Confusing...

    So what to do about it ?

    Well, you can use the hack the author suggests in the link I gave you. In summary, for people in a hurry, he uses en event to run a callback function when the script is loaded. So you can put all the code using the remote library in the callback function. E.G :

    function loadScript(url, callback)
    {
        // adding the script tag to the head as suggested before
       var head = document.getElementsByTagName('head')[0];
       var script = document.createElement('script');
       script.type = 'text/javascript';
       script.src = url;
    
       // then bind the event to the callback function 
       // there are several events for cross browser compatibility
       script.onreadystatechange = callback;
       script.onload = callback;
    
       // fire the loading
       head.appendChild(script);
    }
    

    Then you write the code you want to use AFTER the script is loaded in a lambda function :

    var myPrettyCode = function() {
        // here, do what ever you want
    };
    

    Then you run all that :

    loadScript("my_lovely_script.js", myPrettyCode);
    

    Ok, I got it. But it's a pain to write all this stuff.

    Well, in that case, you can use as always the fantastic free jQuery framework, which let you do the very same thing in one line :

    $.getScript("my_lovely_script.js", function() {
        alert("Script loaded and executed.");
        // here you can use anything you defined in the loaded script
    });
    
    0 讨论(0)
  • 2020-11-22 07:25

    If you have jQuery loaded already, you should use $.getScript.

    This has an advantage over the other answers here in that you have a built in callback function (to guarantee the script is loaded before the dependant code runs) and you can control caching.

    0 讨论(0)
  • 2020-11-22 07:25

    I am lost in all these samples but today I needed to load an external .js from my main .js and I did this:

    document.write("<script src='https://www.google.com/recaptcha/api.js'></script>");
    
    0 讨论(0)
  • 2020-11-22 07:25

    all the major javascript libraries like jscript, prototype, YUI have support for loading script files. For example, in YUI, after loading the core you can do the following to load the calendar control

    var loader = new YAHOO.util.YUILoader({
    
        require: ['calendar'], // what components?
    
        base: '../../build/',//where do they live?
    
        //filter: "DEBUG",  //use debug versions (or apply some
                            //some other filter?
    
        //loadOptional: true, //load all optional dependencies?
    
        //onSuccess is the function that YUI Loader
        //should call when all components are successfully loaded.
        onSuccess: function() {
            //Once the YUI Calendar Control and dependencies are on
            //the page, we'll verify that our target container is 
            //available in the DOM and then instantiate a default
            //calendar into it:
            YAHOO.util.Event.onAvailable("calendar_container", function() {
                var myCal = new YAHOO.widget.Calendar("mycal_id", "calendar_container");
                myCal.render();
            })
         },
    
        // should a failure occur, the onFailure function will be executed
        onFailure: function(o) {
            alert("error: " + YAHOO.lang.dump(o));
        }
    
     });
    
    // Calculate the dependency and insert the required scripts and css resources
    // into the document
    loader.insert();
    
    0 讨论(0)
提交回复
热议问题