YepNope/Modernizr 回调,包含全局 JavaScript 变量和 Internet Explorer

YepNope/Modernizr callbacks with global JavaScript variables and Internet Explorer

本文关键字:变量 JavaScript Internet Explorer 包含全 Modernizr 回调 YepNope      更新时间:2023-09-26

谁能解释为什么在Internet Explorer中,代码示例1不起作用,而代码示例2不起作用?

代码 1(无法正常工作(

Modernizr.load([
    {
        load: [
            '../includes/css/foo.css',
            '../includes/js/foo.js',
            '../includes/js/bar.js'
        ],
        complete: function() {
            initBar();
        }
    }
]);

代码 2(功能(

Modernizr.load([
    {
        load: [
            '../includes/css/foo.css',
            '../includes/js/foo.js',
            '../includes/js/bar.js'
        ],
        complete: function() {
            window.initBar();
        }
    }
]);

酒吧.js

var initBar = function() {
    // code here
};

它在其他浏览器中工作正常。我尝试将块移动到头部以及页面下方。我也尝试将回调的内容包装在 $(document).ready() 中,但没有一个使用代码 1。

我特别遇到的错误是:

SCRIPT5009: « initBar » est indéfini

这几乎就像在资源完成加载之前执行回调一样,但如果是这种情况,那么为什么代码示例 2 有效?

我还会注意到,刷新时页面加载正常(很可能是由于资源被缓存的事实(,但在清除缓存后它也能加载正常。清除缓存后,我必须重新启动浏览器会话才能重现问题。

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

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

IE浏览器:

   HTML1300: Une navigation s’est produite.
   Fichier : test18.php
   before .load() called
   before bar accessed
   typeof bar = undefined
   typeof window.bar = undefined
   SCRIPT5009: « bar » est indéfini
   Fichier : test18.js, ligne : 14, colonne : 13
   before bar defined

因此,complete函数似乎在定义bar之前执行。我觉得很奇怪,window.bar也是未定义的,但有效......

火狐

[02:10:46,448] "before .load() called"
[02:10:47,184] "before bar defined"
[02:10:47,184] "before bar accessed"
[02:10:47,184] "typeof bar = object"
[02:10:47,184] "typeof window.bar = object"

before .load() called
before bar defined
before bar accessed
typeof bar = object
typeof window.bar = object

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

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

以下是我能想到的不同浏览器中可能有所不同的事情:

  1. 加载脚本的确切时间,从而调用complete()函数的时间。

  2. 浏览器中的缓存(可能会影响加载计时(。

  3. 由于您通过将initBar赋值给变量而不是常规function initBar()定义来定义因此,在该行代码执行之前,该函数将不存在,而function initBar()将在脚本解析时存在。

  4. 确保 yepnope 加载库的版本为 1.5 或更高版本(我不知道对应于哪个 modernizr 版本。 .load()的yepnope文档是这样说的:"在1.5之前的yepnope版本中,[调用完整函数时]可能会不时变化"。

  5. 此页面上有注释,除非存在加载项,否则 yepnope 库可能不会等待.css文件加载后调用完整的回调。 我不知道这是否抛弃了整个完整的时间,或者我注意到您的加载列表中确实有.css个文件。

因此,这是我建议调试的内容:

1( 将你的初始化栏定义更改为:

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加载。


这是一个替换脚本

,可以动态加载多个脚本来替换 modernizr 错误.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);
    }
}

示例用法:

loadScriptsInParallel([
    '../includes/js/foo.js',
    '../includes/js/bar.js'
], function() {
    // put code here for when all scripts are loaded
    initBar();
});

工作演示:http://jsfiddle.net/jfriend00/qs44R/

如果您需要按顺序加载它们(由于它们之间的依赖关系,一个接一个(,那么您可以使用以下内容:

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();
}

工作演示:http://jsfiddle.net/jfriend00/9aVLW/