谁能解释为什么在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/