Javascript, execute scripts code in order inserted into dom tree

前端 未结 5 1524
囚心锁ツ
囚心锁ツ 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:12

    Ok, I think I have now came up with a solution.

    The trick is that we keep track of each script to be loaded and their order as we insert them into the dom tree. Each of their callback is then registered accordingly to their element.

    Then we keep track of when all has finished loading and when they all have, we go through the stack and fire their callbacks.

    var stack = [];
    stack.loaded = 0;
    function loadScriptNew(path, callback) {
            var o = { callback: callback };
            stack.push(o);
    
            loadScript(path, function() {
                    o.callbackArgs = arguments;
                    stack.loaded++;
                    executeWhenReady();
            });
    }
    
    function executeWhenReady() {
            if ( stack.length == stack.loaded ) {
                    while(stack.length) {
                            var o = stack.pop();
                            o.callback.apply(undefined, o.callbackArgs);
                    }
    
                    stack.loaded = 0;
            }
    }
    

    // The above is what has been added to the code in the question.

    function loadScript(path, callback) {
            var element = document.createElement('script');
            element.setAttribute("type", 'text/javascript');
            element.setAttribute("src", path);
    
            return loadElement(element, callback);
    }
    
    function loadElement(element, callback) {
            element.setAttribute("defer", "");
            // element.setAttribute("async", "false");
    
            element.loaded = false;
    
            if (element.readyState){  // IE
                    element.onreadystatechange = function(){
                            if (element.readyState == "loaded" || element.readyState == "complete"){
                                    element.onreadystatechange = null;
    
                                    loadElementOnLoad(element, callback);
                            }
                    };
            } else {                 // Others
                    element.onload = function() {
                            loadElementOnLoad(element, callback);
                    };
            }
    
            (document.head || document.getElementsByTagName('head')[0] || document.body).appendChild(element);
    
            return element;
    }
    
    function loadElementOnLoad(element, callback) {
            if (element.loaded != true) {
                    element.loaded = true;
                    if ( callback ) callback(element);
            }
    }
    
    loadScriptNew("http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js",function() {
            alert(1);
    });
    
    loadScriptNew("http://ajax.googleapis.com/ajax/libs/chrome-frame/1.0.3/CFInstall.min.js",function() {
            alert(2);
    });
    

    Ok, some of you might argue that there is missing info in the question, which I will give you and here we are actually just solving the callback. You are right. The code in the script is still executed in the wrong order, but the callback is now.

    But for me this is good enough, as I intend to wrap all code that is loaded in a method call, alá AMD, such as a require or define call and will put on stack there, and then fire them in the callback instead.

    I am still hoping out for Asad and his iframe solution, which I believe might provide the best answer to this question. For me though, this solution will solve my problems :)

提交回复
热议问题