HTML <script defer> 可以在 <script async> 之前执行吗?

Can HTML <script defer> execute before <script async>?

我要问的是一个已经深入探讨过的问题,而且我的问题有很多接近的答案,但我没能找到一个简单问题的确切答案.

我知道延迟脚本 运行 按照它们在页面上出现的顺序,但只有在构建 DOM 之后,我会尽快得到异步脚本 运行尽可能,我知道没有人阻止 HTML 解析器。

这里的问题是:是否存在延迟脚本可以在所有异步脚本执行之前执行的情况?本质上,如果 HTML 解析器已经解析了整个文档并准备好 运行 延迟脚本但是仍然有一些异步脚本尚未加载,它是否会等待这些异步脚本加载(并执行),还是 运行 延迟脚本?

谢谢!

从一个非常简单的测试来看,似乎 defer 不会等待 async 脚本加载...但是(总有一个但是)它似乎也取决于浏览器。

我 运行 在 Chrome 41、Firefox 36 和 Internet Explorer 11 上进行了测试,Chrome 和 FF 得到了相同的结果(deferasync) 但在 IE 上的结果不同(async 总是在 defer 之前执行)。

如果 IE 忽略 async 属性(立即解析并执行代码),这可以解释,但根据 W3Schools and MDN,IE10 支持 async。所以我想,IE 以不同于其他浏览器的方式处理异步调用,使其加载并执行 faster/before 整个页面被解析(然后 运行ning 在延迟脚本之前)。

这是我用于测试的 HTML 代码:

<!doctype html>
<html>

    <head>
        <title>Test</title>
        <script type="text/javascript" src="./async.js"></script>
        <script type="text/javascript" src="./defer.js"></script>
    </head>

    <body>
        Testing
    </body>

</html>

现在async.js的内容:

console.log("async");

以及defer.js的内容:

console.log("defer");

如果我运行它"as is",控制台结果是:

async
defer

这是意料之中的,因为脚本是在浏览器继续解析页面之前立即执行的。

现在我们来玩一下 asyncdefer,看看结果:


代码:

<script type="text/javascript" src="./defer.js" defer></script>
<script type="text/javascript" src="./async.js" async></script>

结果:

defer
async

[注意:这是 Chrome 和 Firefox 上的结果;对于 IE,控制台是异步的然后延迟]

Defer.js 在 async.js 之前执行。不过可能是因为 async.js 放在代码的后面,所以让我们交换它们。


代码:

<script type="text/javascript" src="./async.js" async></script>
<script type="text/javascript" src="./defer.js" defer></script>

结果:

defer
async

[注意:这是 Chrome 和 Firefox 上的结果;对于 IE,控制台是异步的然后延迟]

Defer.js 仍然在 async.js 之前执行,即使之前调用过 async.js。所以回答你的问题:是的,在某些情况下,延迟脚本会在所有异步脚本加载和解析之前执行。


代码:

<script type="text/javascript" src="./async.js"></script>
<script type="text/javascript" src="./defer.js" defer></script>

<script type="text/javascript" src="./defer.js" defer></script>
<script type="text/javascript" src="./async.js"></script>

结果:

async
defer

这个结果是预期的,因为在这种情况下 async.js 被立即执行,并且 defer 等待页面解析(即使我们交换 script 位置也会得到相同的结果) .


最后测试一个在没有 async/defer 之前调用的异步脚本(不需要反过来测试,因为它会在调用异步之前立即执行):

代码:

<script type="text/javascript" src="./async.js" async></script>
<script type="text/javascript" src="./defer.js"></script>

结果:

defer
async

是的,理论上可以在具有 defer 脚本的脚本之后执行具有 async 属性的脚本。您应该相应地编写脚本。

即使在实践中不会发生这种情况,您仍然应该以这种期望编写脚本,因为规范不保证 async 脚本将在 defer 脚本之后执行,因此浏览器可以自由地以这种方式执行。