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>