可以信任script.readyState来检测动态脚本加载的结束吗?

时间:2009-12-18 17:51:15

标签: javascript scripting dynamic load labjs

我使用动态脚本加载来减少初始页面加载的持续时间。为了确保脚本定义的函数和对象可以访问,我需要确保脚本已经完全加载。

我为此已经开发了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回调过早被解雇了。

我会在回答这个问题时发表自己的研究结果,并希望从社区中收集进一步的证据和反馈。

5 个答案:

答案 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中的类似结果。

不接受......

只是加载和错误。