在 HTML 文档中嵌入 JavaScript 时,放置 <script>
标记和包含 JavaScript 的合适位置在哪里?我似乎记得您不应该将它们放在 <head>
部分中,但是放在 <body>
部分的开头也很糟糕,因为必须在页面完全呈现之前解析 JavaScript(或类似的东西)。这似乎将 <body>
部分的 末尾 作为 <script>
标签的逻辑位置。
那么,放置 <script>
标签 的 正确位置在哪里?
(这个问题引用 了这个问题,其中建议 JavaScript 函数调用应该从 <a>
标记移动到 <script>
标记。我专门使用 jQuery,但更一般的答案也是合适的。)
原文由 mipadi 发布,翻译遵循 CC BY-SA 4.0 许可协议
当浏览器加载带有
<script>
标签的网站时,会发生以下情况:获取 HTML 页面(例如 index.html )
开始解析 HTML
解析器遇到引用外部脚本文件的
<script>
标记。浏览器请求脚本文件。同时,解析器会阻止并停止解析页面上的其他 HTML。
一段时间后,脚本被下载并随后执行。
解析器继续解析 HTML 文档的其余部分。
第 4 步会导致糟糕的用户体验。在您下载所有脚本之前,您的网站基本上会停止加载。如果用户讨厌一件事,那就是等待网站加载。
为什么会发生这种情况?
任何脚本都可以通过
document.write()
或其他 DOM 操作插入自己的 HTML。这意味着解析器必须等到脚本下载并执行后才能安全地解析文档的其余部分。毕竟,脚本 可以 在文档中插入自己的 HTML。但是,大多数 JavaScript 开发人员不再 在 文档加载时操作 DOM。相反,他们会等到文档加载完毕后再进行修改。例如:
JavaScript:
因为您的浏览器不知道 my-script.js 在下载并执行之前不会修改文档,因此解析器停止解析。
过时的推荐
解决这个问题的旧方法是将
<script>
标签放在<body>
的底部,因为这样可以确保解析器直到最后都不会被阻塞。这种方法有其自身的问题:在整个文档被解析之前,浏览器无法开始下载脚本。对于具有大型脚本和样式表的大型网站,能够尽快下载脚本对性能非常重要。如果您的网站在 2 秒内未加载,人们将转到另一个网站。
在最佳解决方案中,浏览器会尽快开始下载您的脚本,同时解析文档的其余部分。
现代方法
今天,浏览器支持脚本的
async
和defer
属性。这些属性告诉浏览器在下载脚本时继续解析是安全的。异步
具有 async 属性的脚本是异步执行的。这意味着脚本在下载后立即执行,同时不会阻塞浏览器。
这意味着脚本 2 可能在脚本 1 之前下载并执行。
根据 http://caniuse.com/#feat=script-async ,97.78% 的浏览器都支持这一点。
推迟
具有 defer 属性的脚本按顺序执行(即首先执行脚本 1,然后执行脚本 2)。这也不会阻止浏览器。
与异步脚本不同,延迟脚本仅在加载整个文档后执行。
根据 http://caniuse.com/#feat=script-defer ,97.79% 的浏览器都支持这一点。 98.06% 至少部分支持它。
关于浏览器兼容性的重要说明:在某些情况下,Internet Explorer 9 和更早版本可能会乱序执行延迟脚本。如果您需要支持这些浏览器,请先阅读 此 内容!
(要了解更多信息并查看异步、延迟和普通脚本之间差异的一些非常有用的视觉表示,请查看此答案的参考部分的前两个链接)
结论
当前的最新技术是将脚本放在
<head>
标记中并使用async
或defer
属性。这允许您的脚本尽快下载,而不会阻止您的浏览器。好消息是您的网站仍应在 2% 的不支持这些属性的浏览器上正确加载,同时加快其他 98% 的速度。
参考
异步与延迟属性
使用 defer 和 async 高效加载 JavaScript
移除阻止渲染的 JavaScript
异步、延迟、模块:可视化备忘单