谁能解释为什么在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改为对象而不是函数。

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库,因此您可以在其中找到其详细文档。

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


脚本的确切加载时间,以及complete()函数被调用的时间。
浏览器中的缓存(可能会影响加载时间)。
因为要通过将initBar分配给变量而不是常规的function initBar()定义来定义function initBar(),所以该函数将不存在,直到执行该行代码,而.load()在脚本解析时就存在。
确保您使用的是yepnope加载库的1.5版或更高版本(我不知道对应的现代化版本。console.log()的yepnope文档说:“在yepnope 1.5之前的版本中,此[当完整功能为被称为]可能会不时变化”
this page上有一些注释,除非您有外接程序,否则yepnope库在调用完整的回调之前可能不会等待.css文件加载。我不知道这是否会拖延整个完整时间,或者我注意到您的加载列表中确实包含.css文件。


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

1)将您的initBar定义更改为此:

function initBar() {
    // code here
}


2)确保您的initBar定义在适当的范围内,并且可以从其他代码访问。请注意是否存在其他功能(例如onload,document.ready等)中可能无法访问的功能。

3)插入一些.load()语句,以进行一些定时调试:

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
}


然后,查看事物以什么顺序出现,以及typeof语句怎么说。这里的想法是尝试找出事情是按错误的顺序执行还是作用域错误。

4)尝试分别加载.css文件,以免影响.js加载。



这是一个替换脚本,该脚本可以动态加载多个脚本,以替换现代的越野车.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/

关于javascript - 具有全局JavaScript变量和Internet Explorer的YepNope/Modernizr回调,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20532727/

10-11 03:42