JavaScript 的 document.write 内联脚本执行顺序
-
01-07-2019 - |
题
我有以下脚本,其中第一个和第三个 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 以像所有其他正常浏览器一样工作?
注意事项:代码片段是一个非常简单的重现。它是在服务器上生成的,第二个脚本是唯一发生变化的内容。这是一个很长的脚本,之所以在它之前和之后有两个脚本,是为了让浏览器缓存它们,并且代码的动态部分会尽可能小。它也可能使用不同的生成代码在同一页面中多次出现。
解决方案 2
我找到了更符合我喜好的答案:
<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>
这将推迟两者的加载 期间 和 后 直到页面加载完成。
我想这已经是我能得到的最好的了。希望有人能够给出更好的答案。
其他提示
不,这是 Internet Explorer 的行为。
如果动态附加脚本,IE、Firefox 和 Chrome 都会以异步方式下载脚本。
Firefox 和 Chrome 将等待所有异步请求返回,然后按照脚本在 DOM 中附加的顺序执行脚本,但 IE 按照通过网络返回的顺序执行脚本。
由于与外部 JavaScript 文件相比,警报“检索”所需的时间更少,这可能解释了您所看到的行为。
来自克里斯托弗·亨里克森 关于异步脚本加载主题的帖子:
在这种情况下,即IE和Firefox将下载两个脚本,但是Internet Explorer也将按照他们完成下载的顺序执行它们,而Firefox则不同步,但仍按照它们附加在DOM中的顺序执行它们。
在Internet Explorer中,这意味着您的脚本不能彼此依赖,因为执行订单会因网络流量,缓存等方面而有所不同。
考虑使用 Javascript 加载器。它将允许您指定脚本依赖性和执行顺序,同时还可以异步加载脚本以提高速度并消除一些浏览器差异。
这是对其中一些的很好的概述: 基本 JavaScript:前五个脚本加载器.
我使用过 RequireJS 和 LabJS。在我看来,LabJS 没有那么固执己见。
幻灯片 25/26(共 25/26) 这个演示文稿 谈谈不同插入脚本方法的特点。这表明 IE 是唯一能够按顺序执行这些脚本的浏览器。所有其他浏览器将按照它们完成加载的顺序执行它们。如果一个或多个具有内联 js 而不是 src,即使 IE 也不会按顺序执行它们。
建议的方法之一是插入一个新的 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;
编辑:尽管我发布的文章是这么说的,但我的测试表明,如果每个浏览器都有 src,大多数浏览器都会按顺序执行 document.write 脚本,因此,虽然我认为上面的方法是首选方法,但您也可以这样做:
<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>
再次编辑(回复对我自己和其他人的评论):您已经在页面上生成了脚本。无论您正在做什么,都可以移动到另一个生成相同代码块的服务器端脚本。如果您的页面上需要参数,请将它们传递给查询字符串中的脚本。
此外,如果按照您的建议,您多次生成内联脚本,则可以使用相同的方法:
<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 函数,并使用不同的参数调用它......
好吧……期间……
// During.js
during[fish]();
后...
// After.js
alert("After");
fish++
超文本标记语言
<!-- 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>
不过,我倾向于同意这种气味开始出现的方式。特别是,为什么不能将“during”代码生成到动态创建的 js 文件中,然后将其插入?
请注意,动态生成的脚本会 里面 中的函数 第二 文档.写。
在 FF2、IE7 中测试
您可以通过在脚本上定义“onload”(或类似)事件并在事件函数中注入下一个事件来强制顺序执行。这并不是微不足道的,但是有很多例子,这里是一个。
http://www.phpied.com/javascript-include-ready-onload/
我认为像 jQuery 或原型这样的流行库可以帮助解决这个问题。
提供代码:
<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>
在 before.js 中:
alert("Before");
callGeneratedContent();
在 after.js 中:
alert("After");
你必须把生成的行放在前面,否则 FF 会抱怨,因为它在看到函数定义之前执行了 before.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>