我应该在 HTML 标记中放置<脚本> 标记的什么位置?结论

2022-08-29 21:57:29

在 HTML 文档中嵌入 JavaScript 时,放置标记和包含 JavaScript 的适当位置在哪里?我似乎记得你不应该把它们放在章节中,但是放在章节的开头也是不好的,因为在页面完全呈现(或类似的东西)之前,JavaScript必须被解析。这似乎使该部分的结尾成为标记的逻辑位置。<script><head><body><body><script>

那么,放置标签的正确位置在哪里<script>

(这个问题引用了这个问题,其中建议将JavaScript函数调用从标签移动到标签。我专门使用jQuery,但更一般的答案也是合适的。<a><script>


答案 1

以下是浏览器加载带有标记的网站时发生的情况:<script>

  1. 获取 HTML 页面(例如索引.html)
  2. 开始解析 HTML
  3. 解析器遇到引用外部脚本文件的标记。<script>
  4. 浏览器请求脚本文件。同时,解析器会阻止并停止解析页面上的其他 HTML。
  5. 一段时间后,脚本被下载并随后执行。
  6. 解析器继续解析 HTML 文档的其余部分。

步骤#4会导致糟糕的用户体验。您的网站基本上停止加载,直到您下载了所有脚本。如果有一件事是用户讨厌的,那就是等待网站加载。

为什么会发生这种情况?

任何脚本都可以通过或其他 DOM 操作插入自己的 HTML。这意味着解析器必须等到脚本下载并执行完毕后才能安全地解析文档的其余部分。毕竟,脚本可以在文档中插入自己的HTML。document.write()

但是,大多数 JavaScript 开发人员在加载文档不再操作 DOM。相反,他们等到加载文档后再对其进行修改。例如:

<!-- index.html -->
<html>
    <head>
        <title>My Page</title>
        <script src="my-script.js"></script>
    </head>
    <body>
        <div id="user-greeting">Welcome back, user</div>
    </body>
</html>

JavaScript:

// my-script.js
document.addEventListener("DOMContentLoaded", function() {
    // this function runs when the DOM is ready, i.e. when the document has been parsed
    document.getElementById("user-greeting").textContent = "Welcome back, Bart";
});

由于您的浏览器不知道 my-script.js在下载并执行文档之前不会修改文档,因此解析器将停止解析。

过时的建议

解决此问题的旧方法是将标记放在底部,因为这可以确保解析器在结束之前不会被阻止。<script><body>

这种方法有其自身的问题:在解析整个文档之前,浏览器无法开始下载脚本。对于具有大型脚本和样式表的大型网站,能够尽快下载脚本对于性能非常重要。如果您的网站在 2 秒内未加载,用户将转到其他网站。

在最佳解决方案中,浏览器将尽快开始下载脚本,同时解析文档的其余部分。

现代方法

如今,浏览器支持脚本上的 和 属性。这些属性告诉浏览器在下载脚本时继续解析是安全的。asyncdefer

异步

<script src="path/to/script1.js" async></script>
<script src="path/to/script2.js" async></script>

具有异步属性的脚本以异步方式执行。这意味着脚本在下载后立即执行,在此期间不会阻止浏览器。这意味着脚本 2 可能在脚本 1 之前下载并执行。

根据 http://caniuse.com/#feat=script-async,97.78%的浏览器都支持此功能。

推迟

<script src="path/to/script1.js" defer></script>
<script src="path/to/script2.js" defer></script>

具有 defer 属性的脚本按顺序执行(即第一个脚本 1,然后是脚本 2)。这也不会阻止浏览器。

与异步脚本不同,延迟脚本仅在加载整个文档后执行。

根据 http://caniuse.com/#feat=script-defer,97.79%的浏览器都支持此功能。98.06%的人至少部分支持它。

有关浏览器兼容性的重要说明:在某些情况下,Internet Explorer 9 及更早版本可能会无序执行延迟脚本。如果您需要支持这些浏览器,请先阅读本文

(要了解更多信息并查看异步,延迟和普通脚本之间差异的一些非常有用的可视化表示,请查看本答案的参考部分中的前两个链接)

结论

当前最先进的方法是将脚本放在标记中并使用 or 属性。这允许您的脚本尽快下载,而不会阻止您的浏览器。<head>asyncdefer

好消息是,您的网站仍然应该在不支持这些属性的2%的浏览器上正确加载,同时加快其他98%的速度。

引用


答案 2

就在结束正文标记之前,如将脚本放在底部所述:

将脚本放在底部

脚本导致的问题是它们会阻止并行下载。HTTP/1.1 规范建议浏览器每个主机名并行下载的组件不超过两个。如果您从多个主机名提供映像,则可以并行进行两次以上的下载。但是,在下载脚本时,浏览器不会启动任何其他下载,即使在不同的主机名上也是如此。