2009-12-18 29 views
25

我使用动态脚本加载来减少初始页面加载的持续时间。为了确保脚本定义的函数和对象是可访问的,我需要确保脚本已经完全加载。可以信任script.readyState来检测动态脚本加载的结束吗?

为此我开发了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

任何人都可以在jQuery 1.x-master分支中找到当前代码?看起来他们已经退出使用'.onreadystatechange'和'.onload'并用promises替换它们? [Clicky](https://github.com/jquery/jquery/blob/1.x-master/src/ajax.js) – Campbeln 2014-12-10 22:54:49

回答

7

在Opera中,script.readyState属性不能被信任。例如,在Opera 9.64中运行脚本之前,readyState“loaded”可能会被触发。

我在Opera 9中执行了the same test。64和Opera 10,结果不同。

在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的处理程序将仍与值触发了两次“装”,但剧本后两次跑:

# 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还支持onload监听器,因此应该使用其他机制。

根据这些测试的结果,onreadystatechange只能用于检测Internet Explorer中脚本加载的结束,并且不应该在其他浏览器中设置onreadystatechange。

+0

至少,你可以忽略第一个事件。 – 2009-12-18 20:33:29

+2

@Justin约翰逊似乎很尴尬,你会计数“加载”的事件,但只是在Opera? – 2009-12-19 14:06:38

3

在Firefox,Safari和Chrome中,onreadystatechange处理程序nevers被调用。

我创建了一个简短的测试情况下,创建动态脚本只有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中,火狐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不是必需的。

1

在Internet Explorer中,onreadystatechange处理程序在脚本结束后按预期触发。

我在Internet Explorer 6,Internet Explorer 7和Internet Explorer 8中执行的same test,在这些三种浏览器类似的结果(在此浏览器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所述,在不同情况下,您还可能会观察到“加载”和“完成”,或者只是“加载”。

1

我发现Internet Explorer(测试9)不会让你的脚本准备好readyState ==='loaded'。我已经成功地使用这个事件处理程序(当然9)onactivate。之前拉出我的头发。

0

Chrome中出现类似结果。

不接受...

只是onload和onerror。