我使用动态脚本加载来减少初始页面加载的持续时间。为了确保脚本定义的函数和对象可以访问,我需要确保脚本已经完全加载。
我为此已经开发了my own Javascript library,因此对这个主题进行了大量的研究,研究它在不同的库中是如何完成的。 在与此问题相关的讨论中,LABjs的作者凯尔辛普森表示:
LABjs(以及许多其他加载器)设置 “onload”和“onreadystatechange” 在所有脚本元素上,知道这一点 有些浏览器会触发一个,有些浏览器 将解雇另一个......
您可以在the current version of jQuery as of this writing, v1.3.2中找到相关示例:
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function(){
if ( !done && (!this.readyState ||
this.readyState == "loaded" || this.readyState == "complete") ) {
done = true;
success();
complete();
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
head.removeChild( script );
}
};
这是最先进的技术,但在分析Opera 9.64中的一个奇怪行为时,我得出的结论是,使用这种技术,onload回调过早被解雇了。
我会在回答这个问题时发表自己的研究结果,并希望从社区中收集进一步的证据和反馈。
答案 0 :(得分:8)
在Opera中,script.readyState属性不可信任。例如,在脚本在Opera 9.64中运行之前,可能会触发readyState“loaded”。
我在Opera 9.64和Opera 10中执行the same test,结果不同。
在Opera 9.64中,onreadystatechange处理程序在脚本运行之前和之后一次被触发两次。 readyState属性在两种情况下都被“加载”,这意味着无法信任此值来检测脚本加载的结束:
# Fri Dec 18 2009 17:54:43 GMT+0100
# Opera/9.64 (Windows NT 5.1; U; en) Presto/2.1.1
Test for script.readyState behavior started
Added script with onreadystatechange handler
readystatechange: loaded
test1.js: Start
test1.js: Start of closure
test1.js: End of closure
readystatechange: loaded
在Opera 10中,onreadystatechange处理程序仍然使用值“loaded”被触发两次,但是在脚本运行后两次都被激活:
# Fri Dec 18 2009 18:09:58 GMT+0100
# Opera/9.80 (Windows NT 5.1; U; en) Presto/2.2.15 Version/10.10
Test for script.readyState behavior started
Added script with onreadystatechange handler
test1.js: Start
test1.js: Start of closure
test1.js: End of closure
readystatechange: loaded
readystatechange: loaded
这些不同的行为表明onreadystatechange不是检测Opera加载脚本结束的可靠方法。由于Opera也支持onload侦听器,因此应该使用其他机制。
根据这些测试的结果,onreadystatechange只应用于检测Internet Explorer中脚本加载的结束,不应在其他浏览器中设置。
答案 1 :(得分:3)
在Firefox,Safari和Chrome中,会调用onreadystatechange处理程序。
我创建了一个简短的测试用例,创建了一个只有onreadystatechange处理程序集的动态脚本:
<script type="text/javascript" language="javascript">
bezen.log.info(new Date(),true);
bezen.log.info(navigator.userAgent,true);
// Activate logs
bezen.log.on();
bezen.log.info('Test for script.readyState behavior started');
var script = document.createElement('script');
script.src = 'test1.js';
script.onreadystatechange = function(){
bezen.log.info('readystatechange: '+script.readyState);
};
document.body.appendChild(script);
bezen.log.info('Added script with onreadystatechange handler');
</script>
我在Firefox 2,Firefox 3,Firefox 3.5,Safari 3,Safari 4和Chrome 3中的本地文件上执行了测试,并得到了类似的结果(此处记录在FF 3.5中的日志):
Fri Dec 18 2009 17:53:58 GMT+0100
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6
Test for script.readyState behavior started
Added script with onreadystatechange handler
test1.js: Start
test1.js: Start of closure
test1.js: End of closure
永远不会调用onreadystatechange。在这些浏览器中,只有onload侦听器对于检测脚本加载的结束很有用,不需要onreadystatechange。
答案 2 :(得分:1)
在Internet Explorer中,onreadystatechange处理程序在脚本结束后按预期触发。
我在Internet Explorer 6,Internet Explorer 7和Internet Explorer 8中执行了same test,在这三种浏览器中都有类似的结果(此处记录在Internet Explorer 6中的日志):
Fri Dec 18 18:14:51 UTC+0100 2009
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Test for script.readyState behavior started
Added script with onreadystatechange handler
test1.js: Start
test1.js: Start of closure
test1.js: End of closure
readystatechange: complete
在这里,使用本地文件进行测试时,readyState总是“完成”,并且在几次页面刷新后它仍然是相同的。
但是,如this post by Nicholas C. Zakas所述,您可能会在不同情况下观察到“已加载”和“已完成”,或只是“已加载”。
答案 3 :(得分:1)
我发现Internet Explorer(在9中测试)在readyState ==='loaded'时,并不总是准备好你的脚本。我已成功使用此事件处理程序(当然在9中) onactivate 。之前是拔我的头发。
答案 4 :(得分:0)
Chrome中的类似结果。
不接受......
只是加载和错误。