阻止IE加载动态包含的脚本两次

我在misc中包含了一些相关的内容。 通过在标记的末尾附近添加标记来添加网页,然后加载其他javascript文件。 这个流程有点复杂,所以在问我的问题之前我会尝试解释它:

  • 浏览器加载一个页面,其元素靠近元素的末尾
  • 脚本标记的src属性指向javascript文件(在某些情况下)注入第二个元素
  • 注入的元素的src属性指向另一个javascript文件,最终在页面的相应部分注入一些内容。

我们使用这种两阶段方法在决定是否包含最终内容之前能够进行一些基本处理,这可能需要一些时间来加载。

问题是IE8(可能是旧版本)加载最后一次javascript两次。 似乎设置src属性的行为将触发加载,但是将脚本标记附加到DOM。 有什么方法可以避免这种情况吗?

我已经创建了一个问题的简单演示 。 如果您有某种方式来跟踪HTTP请求,您将看到IE8加载js_test2.js两次。

根本区别在于,IE首次将其添加到父元素的childNodes时执行脚本元素,无论父元素是否实际位于文档中。 其他浏览器仅在将脚本添加到文档的childNodes树中的节点时才执行脚本。

jQuery的domManip函数(jQuery 1.3.2的第524行),由append和其他类似的jQuery方法调用,试图变得聪明并为最终解析的HTML中找到的任何元素调用evalScript来执行脚本(通过执行AJAX请求,如果需要外部脚本)。 (实际的脚本元素已从已解析的childNodes中删除,以阻止它们在插入文档时执行,大概是这样只有当包含它们的内容一次附加到多个元素中时,脚本才会执行一次。)

但是,因为先前的clean函数在解析HTML时将脚本元素附加到包装器div,所以IE已经执行了脚本。 所以你得到两次执行。

最好的办法是避免在使用脚本执行任何操作时使用domManip函数,例如append HTML字符串。

实际上,忘记将您的内容放在序列化的HTML字符串中并让jQuery解析它; 只需要更可靠的纯DOM方式:

 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操作完全没有任何疑问。它应该修复浏览器错误,但是愚蠢的-regex处理在我看来可能会导致尽可能多的问题。)

顺便提一下这个初始电话:

 document.write(unescape("%3Cscript src='js_test1.js' type='text/javascript'%3E%3C/script%3E")); 

你不需要在这里取景; 我不知道为什么这么多人这么做。 序列需要在内联脚本中避免,因为它会结束标记,如果你正在做XHTML <&应该避免(或者]]>如果你正在使用CDATA包装器) ,但只有JavaScript字符串文字有一种更简单的方法来完成所有这些:

 document.write('\x3Cscript src="js_test1.js" type="text/javascript">\x3C/script>")); 

我已经看到在类似情况下在其他版本的IE上发生这种行为(例如克隆节点),我从来不知道如何阻止脚本执行两次,所以我最后做的是添加一个警卫在脚本代码上不要运行两次。 它是这样的:

 if (typeof(loaded) == 'undefined') { // the whole code goes in here var loaded = true; } 

如果找不到阻止脚本执行两次的方法,您可能希望尝试使用该方法。

似乎jquery使用XmlHttpRequest获取js_test2的第二个实例。

为什么我不知道,但你需要调查它的JQuery的行为。

您可以在加载之前检查文档中是否已有脚本 –

 function fetchscript(url, callback){ var S= document.getElementsByTagName('script'), L= S.length; while(L){ if(S[--L].src== url) return true; } //create and append script and any callbacks } 

我发现同样的问题,只发生在IE中。

jQuery的html()方法链是: html>append>domManip>clean

clean()方法使用innerHTML make string to DOM,IE中的innerHTML有一个bug script标签会立即加载(第一次加载),jQuery evalScript脚本标签在domManip方法结束时(ajax加载)。然后在IE中加载两次脚本文件。

我认为jQuery应该解决这个问题,更新clean()方法

这可能是因为当您已经在元素中时使用document.write 。 您是否尝试过追加而不是document.write