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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1929742/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 21:56:12  来源:igfitidea点击:

Can script.readyState be trusted to detect the end of dynamic script loading?

javascriptscriptingdynamicloadlabjs

提问by Eric Bréchemier

I use dynamic script loading to reduce the duration of the initial page load. To ensure that the functions and objects defined by a script are accessible, I need to ensure that the script has been fully loaded.

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

I have developed my own Javascript libraryto this end, and thus did quite a lot of research on the subject, studying how it's done in different libraries. During a discussion related to this issue, Kyle Simpson, the author of LABjs, stated that:

为此,我开发了自己的 Javascript 库,因此对该主题进行了大量研究,研究了它在不同库中的实现方式。在与此问题相关的讨论中,LABjs的作者 Kyle Simpson表示:

LABjs (and many other loaders) set both "onload" and "onreadystatechange" on all script elements, knowing that some browsers will fire one, and some will fire the other...

LABjs(和许多其他加载器)在所有脚本元素上都设置了“onload”和“onreadystatechange”,知道有些浏览器会触发一个,而有些浏览器会触发另一个......

You can find an example of this in the current version of jQuery as of this writing, v1.3.2:

撰写本文时,您可以在当前版本的 jQuery 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 );
    }
};

That's the state of the art, but during the analysis of a strange behavior in Opera 9.64, I came to the conclusion that, using this technique, the onload callback got fired too early.

这是最先进的技术,但在分析 Opera 9.64 中的一个奇怪行为时,我得出的结论是,使用这种技术,onload 回调过早地被触发。

I will post my own findings in answer to this question, and would like to gather further evidence and feedback from the community.

我将发布我自己的发现来回答这个问题,并希望从社区收集进一步的证据和反馈。

采纳答案by Eric Bréchemier

In Opera, the script.readyState property cannot be trusted. For example, the readyState "loaded" may be fired before the script runs in Opera 9.64.

在 Opera 中,script.readyState 属性不可信。例如,可以在 Opera 9.64 中运行脚本之前触发 readyState“加载”。

I performed the same testin Opera 9.64 and Opera 10, with different results.

我在 Opera 9.64 和 Opera 10 中进行了相同的测试,结果不同。

In Opera 9.64, the onreadystatechange handler gets fired twice, once before and once after the script runs. The readyState property is "loaded" in both cases, which means that this value cannot be trusted to detect the end of the script loading:

在 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

In Opera 10, the onreadystatechange handler still gets fired twice with the value "loaded", but both times after the script ran:

在 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

These different behaviors indicate that onreadystatechange is not a reliable way to detect the end of a script loading in Opera. Since Opera also supports the onload listener, this other mechanism should be used instead.

这些不同的行为表明 onreadystatechange 不是检测 Opera 中脚本加载结束的可靠方法。由于 Opera 还支持 onload 侦听器,因此应改用此其他机制。

Based on the results of these tests, onreadystatechange should only be used to detect the end of script loading in Internet Explorer, and it should not be set in other browsers.

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

回答by Eric Bréchemier

In Firefox, Safari and Chrome, the onreadystatechange handler nevers gets called.

在 Firefox、Safari 和 Chrome 中,永远不会调用 onreadystatechange 处理程序。

I created a short test case, creating a dynamic script with only the onreadystatechange handler set:

我创建了一个简短的测试用例,创建了一个仅包含 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>

I performed the test on a local file in Firefox 2, Firefox 3, Firefox 3.5, Safari 3, Safari 4 and Chrome 3, and got similar results (here the logs recorded in FF 3.5):

我在 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

The onreadystatechange never gets called. In these browsers, only the onload listener is useful to detect the end of a script loading, the onreadystatechange is not needed.

onreadystatechange 永远不会被调用。在这些浏览器中,只有 onload 侦听器可用于检测脚本加载的结束,不需要 onreadystatechange。

回答by Eric Bréchemier

In Internet Explorer, the onreadystatechange handler fires as expected, after the end of the script.

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

I performed the same testin Internet Explorer 6, Internet Explorer 7 and Internet Explorer 8, with similar results in these three browsers (here the logs recorded in Internet Explorer 6):

我在 Internet Explorer 6、Internet Explorer 7 和 Internet Explorer 8 中执行了相同的测试,在这三个浏览器中得到了相似的结果(这里是 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

Here, with a test using a local file, the readyState is always "complete", and it was still the same after several page refresh.

在这里,使用本地文件进行测试时,readyState 始终为“完成”,并且在多次页面刷新后仍然相同。

However, as noted in this post by Nicholas C. Zakas, you may also observe "loaded" and "complete", or just "loaded", under different circumstances.

但是,正如Nicholas C. Zakas这篇文章中所指出的,在不同的情况下,您也可能会观察到“加载”和“完成”,或者只是“加载”。

回答by Gus Crawford

I've found that internet explorer (testing in 9) DOESN'T ALWAYS have your script ready when readyState === 'loaded'. I have had success using this event handler (in 9 of course) onactivate. Was pulling my hair out before.

我发现 Internet Explorer(在 9 中测试)在 readyState === 'loaded' 时并不总是准备好您的脚本。我使用这个事件处理程序(当然是 9 个)onactivate取得了成功。以前拔头发。

回答by Cody

Similar results in Chrome.

Chrome 中的结果类似。

Doesn't take onready...

不用准备...

Just onload and onerror.

只是加载和错误。