Javascript, execute scripts code in order inserted into dom tree

前端 未结 5 1502
囚心锁ツ
囚心锁ツ 2021-01-06 05:47

NOT A DUPLICATE AS I HAVE YET TO FOUND A SATISFYING ANSWER ON OTHER THREADS:

  • Load and execute javascript code SYNCHRONOUSLY
  • Loading HTML and Script o
5条回答
  •  北海茫月
    2021-01-06 06:17

    After a while of fiddling around with it, here is what I came up with. Requests for the scripts are sent off immediately, but they are executed only in a specified order.

    The algorithm:

    The algorithm is to maintain a tree (I didn't have time to implement this: right now it is just the degenerate case of a list) of scripts that need to be executed. Requests for all of these are dispatched nearly simultaneously. Every time a script is loaded, two things happen: 1) the script is added to a flat list of loaded scripts, and 2) going down from the root node, as many scripts in each branch that are loaded but have not been executed are executed.

    The cool thing about this is that not all scripts need to be loaded in order for execution to begin.

    The implementation:

    For demonstration purposes, I am iterating backward over the scriptsToExecute array, so that the request for CFInstall is sent off before the request for angularJS. This does not necessarily mean CFInstall will load before angularJS, but there is a better chance of it happening. Regardless of this, angularJS will always be evaluated before CFInstall.

    Note that I've used jQuery to make my life easier as far as creating the iframe element and assigning the load handler is concerned, but you can write this without jQuery:

    // The array of scripts to load and execute
    
    var scriptsToExecute = [
        "http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js?t=" + Date.now(), 
        "http://ajax.googleapis.com/ajax/libs/chrome-frame/1.0.3/CFInstall.min.js?t=" + Date.now()
    ];
    
    
    // Loaded scripts are stored here
    
    var loadedScripts = {};
    
    
    // For demonstration purposes, the requests are sent in reverse order.
    // They will still be executed in the order specified in the array.
    
    (function start() {
        for (var i = scriptsToExecute.length - 1; i >= 0; i--) {
            (function () {
                var addr = scriptsToExecute[i];
                requestData(addr, function () {
                    console.log("loaded " + addr);
                });
            })();
        }
    })();
    
    
    // This function executes as many scripts as it currently can, by
    // inserting script tags with the corresponding src attribute. The
    // scripts aren't reloaded, since they are in the cache. You could
    // alternatively eval `script.code`
    
    function executeScript(script) {
        loadedScripts[script.URL] = script.code
    
        while (loadedScripts.hasOwnProperty(scriptsToExecute[0])) {
            var scriptToRun = scriptsToExecute.shift()
            var element = document.createElement('script');
            element.setAttribute("type", 'text/javascript');
            element.setAttribute("src", scriptToRun);
    
            $('head').append(element);
    
            console.log("executed " + scriptToRun);
        }
    }
    
    
    // This function fires off a request for a script
    
    function requestData(path, loadCallback) {
        var iframe = $("