阻止 IE 加载动态包含的脚本两次 [英] Stop IE from loading dynamically included script twice
问题描述
我在 misc 中包含了一些相关内容.通过在 标签的末尾添加一个
标签,然后加载其他 javascript 文件.流程有点复杂,所以我会在提问之前尝试解释一下:
I am including some related content on misc. web pages by adding a <script>
tag near the end of the <body>
tag, which then loads other javascript files. The flow is a little convoluted, so I’ll try to explain it before asking my question:
- 浏览器加载了一个页面,其中
元素位于
元素的末尾
- 脚本标签的 src 属性指向一个 javascript 文件(在某些情况下)注入第二个
元素
- 注入的
元素的 src 属性指向另一个 javascript 文件,该文件最终在页面的适当部分注入一些内容.
- A browser loads a page with our
<script>
element near the end of the<body>
element - The src attribute of the script tag points to a javascript file which (in some cases) injects a second
<script>
element - The src attribute of the injected
<script>
element points to yet another javascript file, which finally injects some content on the appropriate part of the page.
我们正在使用这种两阶段方法,以便能够在决定是否包含最终内容之前进行一些基本处理,这可能需要一些时间来加载.
We are using this two-stage approach to be able to do some basic processing before deciding whether to include the final content, which could take some time to load.
问题是 IE8(可能还有旧版本)加载了最后一个 javascript 两次.设置 src 属性的行为似乎会触发加载,但将脚本标记附加到 DOM 也会触发加载.有什么办法可以避免这种情况吗?
The problem is that IE8 (and maybe older versions) loads the last javascript twice. It appears that the act of setting the src attribute will trigger a load, but so will appending the script tag to the DOM. Is there any way to avoid this?
我已经创建了该问题的裸机演示.如果您有某种跟踪 HTTP 请求的方法,您将看到 IE8 加载了 js_test2.js 两次.
I have created a bare-bones demo of the problem. If you have some way of tracing the HTTP requests, you will see that IE8 loads js_test2.js twice.
推荐答案
根本区别在于 IE 在第一次将脚本元素添加到父元素的 childNodes 时执行它,而不管父元素实际上是否在文档中.其他浏览器仅在将脚本添加到文档子节点树中的节点时才执行脚本.
The root difference is that IE executes a script element the first time it is added to a parent element's childNodes, regardless of whether the parent element is actually in the document. Other browsers only execute script when it is added to a node inside the document's tree of childNodes.
jQuery 的 domManip
函数(jQuery 1.3.2 的第 524 行),由 append
和其他类似的 jQuery 方法调用,试图聪明地调用 evalScript
用于它在最终解析的 HTML 中找到的任何 元素,以执行脚本(如果外部脚本需要,通过执行 AJAX 请求).(实际脚本元素已从解析的 childNode 中删除,以阻止它们在插入文档时被执行,大概是这样,当包含它们的内容一次附加到多个元素中时,脚本只会执行一次.)
jQuery's domManip
function (line 524 of jQuery 1.3.2), which is called by append
and other similar jQuery methods, tries to be clever and calls evalScript
for any <script>
elements it finds in the final parsed HTML, to execute the script (by doing AJAX requests if necessary for external scripts). (The actual script elements have been removed from the parsed childNodes to stop them getting executed on insertion into the document, presumably so that scripts are only executed once when content containing them is appended into multiple elements at once.)
然而,因为之前的 clean
函数在解析 HTML 时,将脚本元素附加到包装器 div 中,IE 将已经执行脚本.所以你会得到两次处决.
However, because the previous clean
function, whilst parsing the HTML, appended the script element to a wrapper div, IE will have already executed the script. So you get two executions.
最好的做法是避免在使用脚本执行任何操作时将 domManip
函数(如 append
和 HTML 字符串)一起使用.
The best thing to do is avoid using domManip
functions like append
with HTML strings when you're doing anything with scripts.
事实上,忘记将您的内容放在一个序列化的 HTML 字符串中并让 jQuery 解析它;只需使用更可靠的纯 DOM 方式即可:
In fact, forget putting your content in a serialised HTML string and getting jQuery to parse it; just do it the much more reliable plain DOM way:
var s= document.createElement('script');
s.type= 'text/javascript';
s.charset= 'UTF-8';
s.src= 'js_test2.js';
document.getElementById('some_container').appendChild(s);
(老实说,在查看了 clean
函数的令人反胃的源代码后,我对使用 jQuery 的基于 HTML 字符串的 DOM 操作对任何事情都产生了严重的怀疑.它是应该修复浏览器错误,但在我看来,愚蠢的正则表达式处理可能会导致尽可能多的问题.)
(To be honest, after viewing the stomach-churning source code of the clean
function, I'm having serious doubts about using jQuery's HTML-string-based DOM manipulations for anything at all. It's supposed to fix up browser bugs, but the dumb-regex processing seems to me likely to cause as many problems as it solves.)
顺便说一下这个初始调用:
Incidentally with this initial call:
document.write(unescape("%3Cscript src='js_test1.js' type='text/javascript'%3E%3C/script%3E"));
你不需要在这里逃避;我不知道为什么这么多人这样做.在内联脚本中需要避免序列 </
,因为它会结束 <script>
标记,并且如果您正在执行 XHTML <
和 &
也应该避免(或者 ]]>
如果您使用的是 CDATA 包装器),但是有一种更简单的方法来完成所有这些仅使用 JavaScript 字符串文字:
You don't need to unescape here; I don't know why so many people do. The sequence </
needs to be avoided in an inline script as it would end the <script>
tag, and if you're doing XHTML <
and &
should be avoided too (or ]]>
if you're using a CDATA wrapper), but there's an easier way of doing all that with just JavaScript string literals:
document.write('x3Cscript src="js_test1.js" type="text/javascript">x3C/script>"));
这篇关于阻止 IE 加载动态包含的脚本两次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!