JavaScript的document.write内联脚本执行顺序

我有以下脚本,其中第一个和第三个document.writeline是静态的, 第二个是生成的

 <script language="javascript" type="text/javascript"> document.write("<script language='javascript' type='text/javascript' src='before.js'><\/sc" + "ript>"); document.write("<script language='javascript' type='text/javascript'>alert('during');<\/sc" + "ript>"); document.write("<script language='javascript' type='text/javascript' src='after.js'><\/sc" + "ript>"); </script> 

Firefox和Chrome将在Internet Explorer首次显示之前之中之后显示, 之后显示。

我遇到了一篇文章,指出我不是第一个遇到这个问题的人,但是这并不能让我感觉更好。

有谁知道我可以如何设置在所有浏览器的确定性,或黑客IE浏览器工作像所有其他的,理智的浏览器呢?

警告 :代码片段是一个非常简单的repro。 它在服务器上生成,第二个脚本是唯一发生变化的东西。 这是一个很长的脚本,之前和之后有两个脚本的原因,以便浏览器将caching它们,代码的dynamic部分将尽可能小。 在不同的生成代码中,它也可能出现在同一页面中多次。

不,这是Internet Explorer的行为。

如果您dynamic添加脚本,则IE,Firefox和Chrome都将以asynchronous方式下载脚本。

Firefox和Chrome会等待所有asynchronous请求返回,然后按照它们附加在DOM中的顺序执行这些脚本,但是IE按照它们通过线路返回的顺序执行这些脚本。

由于警报比外部JavaScript文件需要更less的时间来“检索”,这可能解释了您所看到的行为。

来自Kristoffer Henriksson 关于asynchronous脚本加载主题的文章 :

在这种情况下,IE和Firefox将同时下载这两个脚本,但Internet Explorer也会按照它们完成下载的顺序执行它们,而Firefox则是以asynchronous方式下载它们,但仍然按照它们在DOM中的顺序执行它们。

在Internet Explorer中,这意味着您的脚本不能彼此依赖,因为执行顺序会因networkingstream量,caching等而异。

考虑使用Javascript加载器。 它可以让你指定脚本的依赖关系和执行顺序,同时也加载你的脚本asynchronous的速度,以及平滑了一些浏览器的差异。

这是其中几个很好的概述: 基本的JavaScript:前五名的脚本加载器 。

我已经使用了RequireJS和LabJS。 在我看来,LabJS是less一些自以为是的。

我已经find了更多我喜欢的答案:

 <script language="javascript" type="text/javascript"> document.write("<script language='javascript' type='text/javascript' src='before.js'><\/sc" + "ript>"); document.write("<script defer language='javascript' type='text/javascript'>alert('during');<\/sc" + "ript>"); document.write("<script defer language='javascript' type='text/javascript' src='after.js'><\/sc" + "ript>"); </script> 

这会推迟加载,直到页面加载完成。

我认为这是我所能得到的。 希望有人能够给出更好的答案。

本演示文稿的幻灯片25/26讲述了插入脚本的不同方法的特点。 这表明IE是唯一能够按顺序执行这些脚本的浏览器。 所有其他浏览器将按照完成加载的顺序执行它们。 即使IE不会执行它们,如果一个或多个有内联js而不是src。

build议的方法之一是插入一个新的DOM元素:

 var se1 = document.createElement('script'); se1.src = 'a.js'; var se2 = document.createElement('script'); se2.src = 'b.js'; var se3 = document.createElement('script'); se3.src = 'c.js'; var head = document.getElementsByTagName('head')[0] head.appendChild(se1); head.appendChild(se2); head.appendChild(se3); 

要生成第二个脚本部分,可以使用脚本生成该内容并传递参数:

 se2.src = 'generateScript.php?params=' + someParam; 

编辑:尽pipe我所选的文章说,我的testing表明,大多数浏览器将执行您的document.write脚本,如果他们每个有一个src,所以虽然我认为上面的方法是首选,你也可以这样做:

 <script language="javascript" type="text/javascript"> document.write("<script type='text/javascript' src='before.js'><\/sc" + "ript>"); document.write("<script type='text/javascript' src='during.php?params=" + params + "'><\/sc" + "ript>"); document.write("<script type='text/javascript' src='after.js'><\/sc" + "ript>"); </script> 

再次编辑(回复给我自己和他人的评论):您已经在您的页面上生成脚本。 无论你在做什么,都可以转移到另一个生成相同代码块的服务器端脚本。 如果您需要页面上的参数,则将其传递给查询string中的脚本。

另外,如果您正如您所build议的那样,您可以使用相同的方法多次生成内联脚本:

 <script language="javascript" type="text/javascript"> document.write("<script type='text/javascript' src='before.js'><\/sc" + "ript>"); document.write("<script type='text/javascript' src='during.php?params=" + params1 + "'><\/sc" + "ript>"); document.write("<script type='text/javascript' src='during.php?params=" + params2 + "'><\/sc" + "ript>"); document.write("<script type='text/javascript' src='during.php?params=" + params3 + "'><\/sc" + "ript>"); document.write("<script type='text/javascript' src='after.js'><\/sc" + "ript>"); </script> 

然而,这开始看起来好像你正在接近这个错误的方式。 如果你正在多次生成一大块代码,那么你应该用一个js函数replace它,然后用不同的参数调用它。

好了… …期间

 // During.js during[fish](); 

后…

 // After.js alert("After"); fish++ 

HTML

 <!-- some html --> <script language="javascript" type="text/javascript"> document.write("<script language='javascript' type='text/javascript' src='before.js'></sc" + "ript>"); document.write("<script language='javascript' type='text/javascript'>during[" + fish + "] = function(){alert('During!' + fish);}</sc" + "ript>"); document.write("<script language='javascript' type='text/javascript' src='during.js'></sc" + "ript>"); document.write("<script language='javascript' type='text/javascript' src='after.js'></sc" + "ript>"); </script> <!-- some other html --> <script language="javascript" type="text/javascript"> document.write("<script language='javascript' type='text/javascript' src='before.js'></sc" + "ript>"); document.write("<script language='javascript' type='text/javascript'>during[" + fish + "] = function(){alert('During!' + fish);}</sc" + "ript>"); document.write("<script language='javascript' type='text/javascript' src='during.js'></sc" + "ript>"); document.write("<script language='javascript' type='text/javascript' src='after.js'></sc" + "ript>"); </script> 

不过,我倾向于认同这种开始闻起来的方式。 特别是,为什么你不能codegen的“期间”dynamic创build的js文件,并插入?

请注意,dynamic生成的脚本进入第二个 document.write中的函数内部
testing了FF2,IE7

您可以通过在脚本上定义“onload”(或类似的)事件来强制执行紧急执行,并在事件函数中插入下一个事件。 这不是微不足道的,但有很多例子,这里有一个例子。

http://www.phpied.com/javascript-include-ready-onload/

我认为像jQuery或原型stream行的图书馆可以帮助这一点。

代码提供:

 <script language="javascript" type="text/javascript"> document.write("<script language='javascript' type='text/javascript'>function callGeneratedContent() { alert('during'); }<\x2Fscript>"); document.write("<script language='javascript' type='text/javascript' src='before.js'><\x2Fscript>"); document.write("<script language='javascript' type='text/javascript' src='after.js'><\x2Fscript>"); </script> 

在.js中:

 alert("Before"); callGeneratedContent(); 

在after.js中:

 alert("After"); 

你必须把生成的行放在第一位,否则FF会在执行之前执行.js,然后才能看到函数定义。

那个怎么样:

 <script> document.write("<script src='before.js'><\/script>"); </script> <script > document.write("<script>alert('during');<\/script>"); </script> <script> document.write("<script src='after.js'><\/script>"); </script>