同步动态加载JavaScript

Eri*_*ver 58 javascript

我正在使用模块模式,我想要做的事情之一就是动态地包含一个外部JavaScript文件,执行该文件,然后使用return { }我模块中文件中的函数/变量.

我无法弄清楚如何轻松地做到这一点.是否有任何标准方法来执行伪同步外部脚本加载?

function myModule() {
    var tag = document.createElement("script");
    tag.type = "text/javascript";
    tag.src = "http://some/script.js";
    document.getElementsByTagName('head')[0].appendChild(tag);

    //something should go here to ensure file is loaded before return is executed

    return {
        external: externalVariable 
    }
}
Run Code Online (Sandbox Code Playgroud)

Sea*_*sey 54

只有一种方法可以同步加载和执行脚本资源,即使用同步XHR

这是如何执行此操作的示例

// get some kind of XMLHttpRequest
var xhrObj = createXMLHTTPObject();
// open and send a synchronous request
xhrObj.open('GET', "script.js", false);
xhrObj.send('');
// add the returned content to a newly created script tag
var se = document.createElement('script');
se.type = "text/javascript";
se.text = xhrObj.responseText;
document.getElementsByTagName('head')[0].appendChild(se);
Run Code Online (Sandbox Code Playgroud)

但是你通常不应该使用同步请求,因为这会阻止其他一切.但话虽如此,当然有适合的情况.

我可能会使用onload处理程序将包含函数重构为异步模式.

  • 请注意,这不适用于尝试在Chrome浏览器上同步加载JS的文件(例如,边缘情况),其中XHR超过`file://`是禁止的. (7认同)
  • 看起来这是跨域失败的.有没有办法对第三方脚本进行动态同步注入?蒂亚. (2认同)
  • 这不等待脚本同步执行. (2认同)

Nei*_*eil 39

接受的答案正确的.

同步加载文件与同步执行文件不同 - 这是OP请求的.

接受的答案加载文件同步,但只是将脚本标记附加到DOM.只是因为appendChild()已经返回并不能保证脚本已经完成执行并且它的成员被初始化以供使用.

实现OP问题的唯一(见警告)方法是如上所述同步加载XHR上的脚本,然后作为文本读取并传入eval()或新的Function()调用并等待该函数返回.这是保证脚本同步加载执行的唯一方法.

我没有评论从UI或安全角度来看这是否是明智的做法,但肯定有用例证明同步加载和执行是合理的.

警告:除非你使用网络工作者,否则只需调用loadScripts();


小智 10

这是我在我的应用程序中用于多个文件加载的代码.

Utilities.require = function (file, callback) {
    callback = callback ||
    function () {};
    var filenode;
    var jsfile_extension = /(.js)$/i;
    var cssfile_extension = /(.css)$/i;

    if (jsfile_extension.test(file)) {
        filenode = document.createElement('script');
        filenode.src = file;
        // IE
        filenode.onreadystatechange = function () {
            if (filenode.readyState === 'loaded' || filenode.readyState === 'complete') {
                filenode.onreadystatechange = null;
                callback();
            }
        };
        // others
        filenode.onload = function () {
            callback();
        };
        document.head.appendChild(filenode);
    } else if (cssfile_extension.test(file)) {
        filenode = document.createElement('link');
        filenode.rel = 'stylesheet';
        filenode.type = 'text/css';
        filenode.href = file;
        document.head.appendChild(filenode);
        callback();
    } else {
        console.log("Unknown file type to load.")
    }
};

Utilities.requireFiles = function () {
    var index = 0;
    return function (files, callback) {
        index += 1;
        Utilities.require(files[index - 1], callBackCounter);

        function callBackCounter() {
            if (index === files.length) {
                index = 0;
                callback();
            } else {
                Utilities.requireFiles(files, callback);
            }
        };
    };
}();
Run Code Online (Sandbox Code Playgroud)

并且可以使用此实用程序

Utilities.requireFiles(["url1", "url2",....], function(){
    //Call the init function in the loaded file.
    })
Run Code Online (Sandbox Code Playgroud)

  • 这是异步,而不是同步! (4认同)
  • 在加载指定的脚本时调用回调函数.不够好吗? (2认同)

Jag*_*er3 5

我能想出的最类似Node.js的实现能够同步加载JS文件,并将它们用作对象/模块

var scriptCache = [];
var paths = [];
function Import(path)
{
    var index = 0;
    if((index = paths.indexOf(path)) != -1) //If we already imported this module
    {
        return scriptCache [index];
    }

    var request, script, source;
    var fullPath = window.location.protocol + '//' + window.location.host + '/' + path;

    request = new XMLHttpRequest();
    request.open('GET', fullPath, false);
    request.send();

    source = request.responseText;

    var module = (function concealedEval() {
        eval(source);
        return exports;
    })();

    scriptCache.push(module);
    paths.push(path);

    return module;
}
Run Code Online (Sandbox Code Playgroud)

示例source(addobjects.js):

function AddTwoObjects(a, b)
{
    return a + b;
}

this.exports = AddTwoObjects;
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

var AddTwoObjects = Import('addobjects.js');
alert(AddTwoObjects(3, 4)); //7
//or even like this:
alert(Import('addobjects.js')(3, 4)); //7
Run Code Online (Sandbox Code Playgroud)