使用全局JavaScript变量和Internet Explorer的YepNope/Modernizer回调

使用全局JavaScript变量和Internet Explorer的YepNope/Modernizer回调,javascript,internet-explorer,global-variables,modernizr,yepnope,Javascript,Internet Explorer,Global Variables,Modernizr,Yepnope,有人能解释为什么在InternetExplorer中,代码示例1不工作,而代码示例2工作吗 代码1(非功能性) 代码2(功能性) bar.js 它可以在其他浏览器中正常工作。我试着将这些块移到页眉部分以及页面下方。我还尝试将回调的内容包装在$(document).ready()中,但没有一个能处理代码1 我得到的具体错误是: 脚本5009:«initBar»est indéfini 这几乎就像是在资源加载完成之前执行回调一样,但如果是这样,那么为什么代码示例2可以工作呢 我还将注意到,在刷新时,

有人能解释为什么在InternetExplorer中,代码示例1不工作,而代码示例2工作吗

代码1(非功能性) 代码2(功能性) bar.js 它可以在其他浏览器中正常工作。我试着将这些块移到页眉部分以及页面下方。我还尝试将回调的内容包装在
$(document).ready()
中,但没有一个能处理代码1

我得到的具体错误是:

脚本5009:«initBar»est indéfini

这几乎就像是在资源加载完成之前执行回调一样,但如果是这样,那么为什么代码示例2可以工作呢

我还将注意到,在刷新时,页面加载良好(很可能是因为资源已缓存),但在清除缓存后,页面也会加载良好。在清除缓存后,我必须重新启动浏览器会话以重现问题

更新: 这个问题不仅仅局限于函数。加载的JS文件中定义的任何全局变量似乎都无法直接访问。如果我在页面顶部加载CSS,而不是异步加载其他资源,也会发生这种情况。事实上,我也注意到了一些以这种方式加载的jQuery插件的问题

更新2: 下面是根据下面的调试说明输出的
console.log()。为了说明这一点,我将bar改为对象而不是函数

Internet Explorer: 因此,
complete
函数似乎在定义
bar
之前执行。我觉得奇怪的是,
window.bar
也没有定义,但仍然可以工作

火狐 铬
Firefox和Chrome似乎都在以正确的顺序加载和执行资源。

首先,您应该知道modernizr中的
.load()
来自于yepnope库,因此您可以在这里找到它的详细文档

以下是我能想到的在不同浏览器中可能不同的东西:

  • 加载脚本的确切时间,以及调用
    complete()
    函数的时间

  • 浏览器中的缓存(这可能会影响加载定时)

  • 因为您是通过将其分配给变量而不是常规的
    函数initBar()
    定义来定义
    initBar
    ,所以在执行该行代码之前,函数将不存在,而
    函数initBar()
    将在脚本解析时存在

  • 确保您使用的是1.5版或更高版本的yepnope加载库(我不知道与哪个Modernizer版本相对应。
    .load()
    的yepnope文档中说:“在1.5之前的yepnope版本中,[调用完整函数时]可能会不时变化”

  • 在调用完整回调之前,yepnope库可能不会等待.css文件加载,除非您有加载项。我不知道这是否会影响整个完整计时,或者我注意到您的加载列表中确实有.css文件

  • 因此,我建议调试以下内容:

    1) 将initBar定义更改为:

    function initBar() {
        // code here
    }
    
    2) 确保initBar定义在正确的范围内,并且可以从其他代码访问。注意其他功能(onload、document.ready等)中可能导致无法访问的内容

    3) 插入一些类似这样的
    console.log()
    语句以执行一些定时调试:

    console.log("before .load() called");
    Modernizr.load([
        {
            load: [
                '../includes/css/foo.css',
                '../includes/js/foo.js',
                '../includes/js/bar.js'
            ],
            complete: function() {
                console.log("before initBar() called");
                console.log("typeof initBar = " + typeof initBar);
                console.log("typeof window.initBar = " + typeof window.initBar);
                initBar();
                console.log("after initBar() called");
            }
        }
    ]);
    
    
    console.log("before initBar() defined");
    function initBar() {
        // code here
    }
    
    然后,看看事情发生的顺序和陈述的类型。这里的想法是试图找出事情是否以错误的顺序执行,或者范围是否错误

    4) 尝试单独加载.css文件,这样就不会影响.js的加载


    这里有一个替换脚本,可以动态加载多个脚本来替换Modernizer buggy
    .load()
    代码。这一个并行加载它们。这仅适用于脚本文件(尽管相同的概念可用于
    .css
    文件)

    function loadScriptsInParallel(scripts, completeCallback) {
        var head = document.getElementsByTagName('head')[0];
        var remaining = scripts.length, i, scriptTag;
    
        function complete() {
            // make sure it's not called again for this script
            this.onreadystatechange = this.onload = function() {};
            // decrement remaining count and check if all are done
            --remaining;
            if (remaining === 0) {
                // all are done call the callback
                completeCallback();
            }
        }
    
        for (var i = 0; i < scripts.length; i++) {
            scriptTag = document.createElement('script');
            scriptTag.type = 'text/javascript';
            scriptTag.src = scripts[i];
            // most browsers
            scriptTag.onload = complete;
            // IE 6 & 7
            scriptTag.onreadystatechange = function() {
                if (this.readyState == 'complete') {
                    complete.apply(this, arguments);
                }
            }
            head.appendChild(scriptTag);
        }
    }
    
    工作演示:

    如果需要按顺序加载它们(由于它们之间的依赖关系,一个接一个),则可以使用以下方法:

    function loadScriptsInSequence(scripts, completeCallback) {
        var head = document.getElementsByTagName('head')[0];
        var remaining = scripts.length, i = 0;
    
        function loadNext() {
            var scriptTag = document.createElement('script');
            scriptTag.type = 'text/javascript';
            scriptTag.src = scripts[i++];
            // most browsers
            scriptTag.onload = complete;
            // IE 6 & 7
            scriptTag.onreadystatechange = function() {
                if (this.readyState == 'complete') {
                    complete.apply(this, arguments);
                }
            }
            head.appendChild(scriptTag);
        }
    
        function complete() {
            // make sure it's not called again for this script
            this.onreadystatechange = this.onload = function() {};
            // decrement remaining count and check if all are done
            --remaining;
            if (remaining === 0) {
                // all are done call the callback
                completeCallback();
            } else {
                loadNext();
            }
        }
    
        loadNext();
    }
    

    工作演示:

    首先,您应该知道Modernizer中的
    .load()
    来自于yepnope库,因此您可以在这里找到它的详细文档

    以下是我能想到的在不同浏览器中可能不同的东西:

  • 加载脚本的确切时间,以及调用
    complete()
    函数的时间

  • 浏览器中的缓存(这可能会影响加载定时)

  • 因为您是通过将其分配给变量而不是常规的
    函数initBar()
    定义来定义
    initBar
    ,所以在执行该行代码之前,函数将不存在,而
    函数initBar()
    将在脚本解析时存在

  • 确保您使用的是1.5版或更高版本的yepnope加载库(我不知道与哪个Modernizer版本相对应。
    .load()
    的yepnope文档中说:“在1.5之前的yepnope版本中,[调用完整函数时]可能会不时变化”

  • 在调用完整回调之前,yepnope库可能不会等待.css文件加载,除非您有加载项。我不知道这是否会影响整个完整计时,或者我注意到您的加载列表中确实有.css文件

  • 因此,我建议调试以下内容:

    1) 将initBar定义更改为:

    function initBar() {
        // code here
    }
    
    2) 确保initBar定义在正确的范围内,并且可以从
    before .load() called
    before bar defined
    before bar accessed
    typeof bar = object
    typeof window.bar = object
    
    function initBar() {
        // code here
    }
    
    console.log("before .load() called");
    Modernizr.load([
        {
            load: [
                '../includes/css/foo.css',
                '../includes/js/foo.js',
                '../includes/js/bar.js'
            ],
            complete: function() {
                console.log("before initBar() called");
                console.log("typeof initBar = " + typeof initBar);
                console.log("typeof window.initBar = " + typeof window.initBar);
                initBar();
                console.log("after initBar() called");
            }
        }
    ]);
    
    
    console.log("before initBar() defined");
    function initBar() {
        // code here
    }
    
    function loadScriptsInParallel(scripts, completeCallback) {
        var head = document.getElementsByTagName('head')[0];
        var remaining = scripts.length, i, scriptTag;
    
        function complete() {
            // make sure it's not called again for this script
            this.onreadystatechange = this.onload = function() {};
            // decrement remaining count and check if all are done
            --remaining;
            if (remaining === 0) {
                // all are done call the callback
                completeCallback();
            }
        }
    
        for (var i = 0; i < scripts.length; i++) {
            scriptTag = document.createElement('script');
            scriptTag.type = 'text/javascript';
            scriptTag.src = scripts[i];
            // most browsers
            scriptTag.onload = complete;
            // IE 6 & 7
            scriptTag.onreadystatechange = function() {
                if (this.readyState == 'complete') {
                    complete.apply(this, arguments);
                }
            }
            head.appendChild(scriptTag);
        }
    }
    
    loadScriptsInParallel([
        '../includes/js/foo.js',
        '../includes/js/bar.js'
    ], function() {
        // put code here for when all scripts are loaded
        initBar();
    });
    
    function loadScriptsInSequence(scripts, completeCallback) {
        var head = document.getElementsByTagName('head')[0];
        var remaining = scripts.length, i = 0;
    
        function loadNext() {
            var scriptTag = document.createElement('script');
            scriptTag.type = 'text/javascript';
            scriptTag.src = scripts[i++];
            // most browsers
            scriptTag.onload = complete;
            // IE 6 & 7
            scriptTag.onreadystatechange = function() {
                if (this.readyState == 'complete') {
                    complete.apply(this, arguments);
                }
            }
            head.appendChild(scriptTag);
        }
    
        function complete() {
            // make sure it's not called again for this script
            this.onreadystatechange = this.onload = function() {};
            // decrement remaining count and check if all are done
            --remaining;
            if (remaining === 0) {
                // all are done call the callback
                completeCallback();
            } else {
                loadNext();
            }
        }
    
        loadNext();
    }