36

我有以下脚本,其中第一个和第三个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 使其像所有其他理智的浏览器一样工作?

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

4

7 回答 7

24

不,这是 Internet Explorer 的行为。

如果您动态附加脚本,IE、Firefox 和 Chrome 都会以异步方式下载脚本。

Firefox 和 Chrome 将等待所有异步请求返回,然后将按照它们在 DOM 中的附加顺序执行脚本,但 IE 按照它们通过网络返回的顺序执行脚本。

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

来自 Kristoffer Henriksson关于异步脚本加载主题的帖子

在这种情况下,IE 和 Firefox 将下载这两个脚本,但 Internet Explorer 也会按照它们完成下载的顺序执行它们,而 Firefox 会异步下载它们,但仍然按照它们在 DOM 中的附加顺序执行它们。

在 Internet Explorer 中,这意味着您的脚本不能相互依赖,因为执行顺序会因网络流量、缓存等而异。

考虑使用 Javascript 加载器。它可以让您指定脚本依赖项和执行顺序,同时还可以异步加载脚本以提高速度并消除一些浏览器差异。

这是对其中一些的很好的概述:Essential JavaScript:前五个脚本加载器。

我使用过 RequireJS 和 LabJS。在我看来,LabJS 不那么固执己见。

于 2008-09-18T17:35:19.390 回答
5

我找到了一个更喜欢我的答案:

<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>

这将延迟加载期间之后的加载,直到页面完成加载。

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

于 2008-09-23T10:04:13.433 回答
1

本演示文稿的幻灯片 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;

编辑:尽管我找到的文章说了什么,但我的测试表明大多数浏览器都会按顺序执行你的 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>

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

此外,如果您按照您的建议多次生成内联脚本,则可以使用相同的方法:

<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 函数替换它并用不同的参数调用它......

于 2008-09-18T16:44:35.767 回答
1

好吧……期间……

// 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>

不过,我倾向于同意这种气味开始的方式。特别是,您为什么不能将“期间”代码生成到动态创建的 js 文件中,然后插入呢?

请注意,动态生成的脚本位于第二个document.write的函数内部。 在FF2、IE7中测试

于 2008-09-18T17:05:08.527 回答
1

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

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

我认为像 jQuery 或原型这样的流行库可以帮助解决这个问题。

于 2008-09-19T11:03:49.713 回答
0

提供的代码:

<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。

于 2008-09-19T09:06:14.147 回答
0

那个怎么样:

<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>
于 2009-04-02T20:23:38.943 回答