范围和脚本加载

时间:2013-09-13 05:17:34

标签: javascript scope

我正在尝试构建一个相当简单的javascript加载器机制。我知道有更多的libs可以做得更好,但我想我可以通过自己尝试来学习。

下面是我的(简化)代码。我的目标是在一个地方保留对所有不同js文件(mod)的引用,即_Mods对象。加载脚本标记后,它将发送代码侦听的自定义事件,并将自己的mod数据(来自_Mods对象)作为参数。每次收到该自定义事件时,计划都将该mod标记为已加载,并最终声明所有mod已加载。然后继续。

我的问题是,当我运行此代码时,控制台将打印mod 'word' loaded!一次,然后退出。如果我在运行!mod.callback.done之前注释掉callback()条件,则会打印mod 'word' loaded!三次。

因此,我意识到mod变量会为每个应该加载的新mod重新分配,并且在加载脚本时应该进行回调,指向前两个mods的数据对象的指针迷路了。

我有什么建议可以重构这个以便从三个不同的 mod中获得回调吗?

(function(window) {
    var ModLoader = (function() {
        var _Mods = {
            game: {
                name: "game",
                src: "js/GameEngine.js"
            },
            dictionary: {
                name: "dictionary",
                src: "js/Dictionary.js"
            },
            word: {
                name: "word",
                src: "js/Word.js"
            }
        },

        _loadMods = function() {
            var head = document.getElementsByTagName('HEAD').item(0);
            for (var property in _Mods) {
                if (_Mods.hasOwnProperty(property)) {
                    var mod = _Mods[property],
                        scriptTag = document.createElement("script");
                    scriptTag.setAttribute("type", "text/javascript");
                    scriptTag.src = mod.src;

                    mod.callback = function() {
                        var customEvent = document.createEvent("Events");
                        customEvent.initEvent("ModLoaded", true, true);
                        customEvent.mod = mod;
                        window.dispatchEvent(customEvent);
                    };

                    scriptTag.onreadystatechange = scriptTag.onload = function() {
                        var state = scriptTag.readyState;
                        if (!mod.callback.done && (!state || /loaded|complete/.test(state))) {
                            mod.callback.done = true;
                            mod.callback();
                        }
                    };

                    (document.body || head).appendChild(scriptTag);    
                }
            }
        },

        _modLoaded = function(event) {
            console.log("mod '" + event.mod.name + "' loaded!");
        };

        return {
            loadMods: _loadMods,
            modLoaded: _modLoaded
        };
    })();

    window.addEventListener("ModLoaded", ModLoader.modLoaded, false);

    ModLoader.loadMods();

})(window);

1 个答案:

答案 0 :(得分:1)

尝试这样的事情:

scriptTag.onreadystatechange = scriptTag.onload = (function(mod) {
    return function(){
        var state = scriptTag.readyState;
        if (!mod.callback.done && (!state || /loaded|complete/.test(state))) {
            mod.callback.done = true;
            mod.callback();
        }
    };
})(mod);