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

时间:2009-11-02 13:08:32

标签: javascript jquery internet-explorer

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

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

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

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

我创建了bare-bones demo问题。如果您有某种方式来跟踪HTTP请求,您将看到IE8加载js_test2.js两次。

6 个答案:

答案 0 :(得分:15)

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

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

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

最好的办法是避免在使用脚本执行任何操作时使用domManipappend函数和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操作完全没有任何疑问。我应该修复它。浏览器错误,但在我看来,愚蠢的正则表达式处理可能会导致尽可能多的问题。)

顺便提一下这个初次通话:

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

你不需要在这里取景;我不知道为什么这么多人这么做。在内联脚本中需要避免序列</,因为它会结束<script>标记,如果您正在执行XHTML <,则应该避免&(或]]>如果您正在使用CDATA包装器,但是只需使用JavaScript字符串文字就可以更轻松地完成所有这些操作:

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

答案 1 :(得分:4)

我已经看到在类似情况下在其他版本的IE上发生这种行为(例如克隆<script>节点)并且我从来不知道如何阻止脚本执行两次,所以我最终得到了什么正在做的是在脚本代码上添加一个防护,因为它不会运行两次。它类似于:

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

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

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

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
}

答案 4 :(得分:1)

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

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

clean()方法使用innerHTML将字符串设为DOM,innerHTML在IE中有script标记将立即加载(第一次加载)的错误,jQuery {{1}在evalScript方法(ajax load)末尾的脚本标记。然后在IE中加载两次脚本文件。

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

答案 5 :(得分:0)

这可能是因为当您已经在document.write元素中时使用<script>。您是否尝试过<head>代替document.write