YepNope / Modernizr使用全局JavaScript变量和Internet Explorer进行回调

时间:2013-12-12 00:26:16

标签: javascript internet-explorer global-variables modernizr yepnope

有人可以解释为什么在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();
        }
    }
]);

bar.js

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

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

我特别提到的错误是:

  

SCRIPT5009:«initBar»estindéfini

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

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

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

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

Internet Explorer:

   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似乎都按正确的顺序加载和执行资源。

1 个答案:

答案 0 :(得分:1)

首先,你应该知道modernizr中的.load()来自yepnope库,所以你可以在那里找到它的详细文档。

以下是我能想到的不同浏览器中可能存在的不同之处:

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

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

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

  4. 确保你的1.3版本或更高版本的yepnope加载库(我不知道对应的是什么modernizr版本。function initBar() { // code here } 的yepnope doc说:“在以前的yepnope版本中1.5 [当调用完整函数时]可能会不时变化“。

  5. this page上有注释,yepnope库可能不会在调用完整回调之前等待.css文件加载,除非你有加载项。我不知道是否会抛弃整个完整时间或者我注意到你的加载列表中有.css文件。

  6. 所以,这是我建议调试的内容:

    1)将initBar定义更改为:

    console.log()

    2)确保您的initBar定义在适当的范围内,并且可以从其他代码访问。注意在其他函数内部(onload,document.ready等等)可能会使其无法访问。

    3)插入一些这样的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 } 语句来进行时序调试:

    .load()

    然后,看看事情的顺序以及声明的类型。这里的想法是试图弄清楚事情是否以错误的顺序执行或者范围是否错误。

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


    这是一个替换脚本,可以动态加载多个脚本来替换modernizr buggy .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();
    });
    

    样本用法:

    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/qs44R/

    如果你需要顺序加载它们(由于它们之间的依赖关系而一个接一个地加载),那么你可以使用它:

    {{1}}

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