我应该将<脚本&标签放在HTML标记的什么位置?

2022-07-22 00:00:00 jquery javascript html
在将JavaScript嵌入到一个HTML文档中时,将<script>标记和包含的JavaScript放在哪里是合适的?我似乎记得您不应该将它们放在<head>节中,但是将它们放在<body>节的开头也是不好的,因为必须在页面完全呈现(或类似的东西)之前解析JavaScript。这似乎将<body>节的结尾保留为<script>标记的逻辑位置。

那么,是放置<script>标记的正确位置吗?

(此问题引用this question,其中建议将JavaScript函数调用从<a>标记移至<script>标记。我专门使用jQuery,但更一般的答案也是合适的。)


解决方案

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

  1. 获取HTML页面(例如index.html)
  2. 开始解析HTML
  3. 分析器遇到引用外部脚本文件的<script>标记。
  4. 浏览器请求脚本文件。同时,分析器会阻止并停止分析页面上的其他HTML。
  5. 一段时间后,将下载该脚本并随后执行。
  6. 分析器继续分析HTML文档的其余部分。
第4步会导致糟糕的用户体验。你的网站基本上会停止加载,直到你下载完所有脚本。如果有一件事是用户讨厌的,那就是等待网站加载。

为什么会发生这种情况?

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

然而,当加载文档时,大多数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>
具有Async属性的脚本是异步执行的。这意味着脚本在下载后立即执行,而不会在此期间阻止浏览器。 这意味着脚本%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和更早版本可能会无序执行延迟的脚本。如果您需要支持这些浏览器,请先阅读this!

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

结论

当前最先进的做法是将脚本放在<head>标记中,并使用asyncdefer属性。这样可以在不阻止浏览器的情况下尽快下载您的脚本。

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

引用

  • async vs defer attributes
  • Efficiently load JavaScript with defer and async
  • Remove Render-Blocking JavaScript
  • Async, Defer, Modules: A Visual Cheatsheet

相关文章