你知道 <script> 标签的放置位置对页面的影响吗
浏览网页时,打开控制台偶尔会看到一些脚本的引入方式,比如 MDN
官网的:
这和我们平时在 <body>
底部引入的方式不太一样,为什么要放在 <head>
中呢?不会阻塞浏览器解析吗?带着这个疑问,我就去查阅相关资料来了解这样做的意义。
不同位置的 <script>
,不同的效果
将 <script>
标签放置在 HTML 文档的 <head>
或 <body>
部分时,会对页面加载和执行产生不同的影响。下面我们就来看看放在不同位置会如何影响页面的渲染:
<script>
放置在 <head>
内的效果
- 页面加载过程中,当浏览器遇到
<script>
标签时,会立即开始下载和执行脚本,然后才会继续渲染页面的其余部分。这会导致浏览器在执行脚本期间暂停页面的渲染过程,直到脚本加载和执行完毕。 - 如果脚本文件很大或加载时间较长,页面的加载过程可能会受到延迟,用户可能会感觉到页面加载速度较慢。
- 如果脚本依赖于页面的某些元素,例如操作
DOM
或绑定事件,当脚本开始执行时,可能会发现页面的元素尚未完全加载,导致脚本无法正常执行,于是报错并且页面停止解析。
<script>
放置在 <body>
底部的效果
- 将脚本放在
<body>
底部可以避免上述问题,因为浏览器会先加载和渲染页面的其余部分,然后再执行脚本。 - 当页面的内容已经加载和渲染完成后,用户可以更快地看到页面的内容,并且页面的交互性会更好。
- 脚本在执行之前,页面的 DOM 结构已经完全生成,因此可以安全地操作 DOM 元素,绑定事件等。
小结
总结起来,将 <script>
放在 <head>
部分可能会导致页面加载延迟和脚本执行受阻,而将脚本放在 <body>
底部可以提高页面加载速度和用户体验。不过,有时候也会有一些特殊情况需要在 <head>
中加载脚本,例如需要在页面加载前执行一些初始化操作或在页面加载过程中有特定的需求。
但如果我就想放在 <head>
中呢,<script>
标签也很贴心的为我们准备了 defer
和 async
属性,下面我们来看看两个属性分别有什么作用。
defer
与 async
defer
和async
属性是用来控制<script>
标签的加载和执行的。
defer
属性
原理
- 当在
<script>
标签中添加defer
属性时,脚本文件会被异步加载。即脚本的下载不会阻塞HTML
文档的解析和渲染过程。 - 脚本文件会按照在
HTML
中出现的顺序依次下载,并且会在HTML
文档解析完毕后(DOMContentLoaded
事件之前)执行。 - 如果有多个带有
defer
属性的脚本,它们的执行顺序是按照它们在HTML
中的出现顺序执行。
有
defer
属性的脚本会阻止DOMContentLoaded
事件,直到脚本被加载并且解析完成。(摘自 MDN 文档)
用法
defer
的用法非常简单,只要在 <script>
标签上添加 defer
属性就好。这是个布尔属性,存在的话值为 true
,否则为 false
:
<!-- 下载完后,按顺序执行 -->
<script src="script1.js" defer></script>
<script src="script2.js" defer></script>
警告:如果缺少
src
属性(即内嵌脚本),该属性不应被使用,因为这种情况下它不起作用。defer
属性对模块脚本没有作用 —— 他们默认defer
。(摘自 MDN 文档)
使用场景
- 当脚本需要依赖于页面的
DOM
结构或需要在页面加载完毕后执行时,可以使用defer
属性。 - 适用于脚本文件相对较大或加载时间较长的情况,因为
defer
属性不会阻塞页面的解析和渲染过程。 - 当需要按照特定顺序执行多个脚本文件时,因为它们会按照在
HTML
中出现的顺序依次执行。
async
属性
原理
- 当在
<script>
标签中添加async
属性时,脚本文件会被并行请求,并尽快解析和执行。和defer
不同的是,带有async
属性的脚本在下载完成后会立即执行,同时阻塞HTML
文档的解析,待脚本执行完后才能继续解析,而不是等待HTML
文档解析完毕。 - 如果有多个带有
async
属性的脚本,它们的执行顺序是不确定的,因为脚本的加载和执行是无法控制的,这一点需要注意。
用法
async
的用法与 defer
完全一致:
<!-- 下载完后,执行顺序不确定!!! -->
<script src="script1.js" async></script>
<script src="script2.js" async></script>
使用场景
- 当脚本与页面的其他内容独立,不依赖于
DOM
结构或其他脚本的执行顺序时,就可以使用async
属性。 - 可以用于独立的统计脚本、广告脚本或与页面展示内容无关的其他脚本。
- 适合利用并行加载提高页面加载性能的情况,因为
async
属性允许脚本文件的加载与页面的解析和渲染并行进行,只在执行脚本时阻塞页面的解析。
小结
使用 defer
和 async
属性可以改善脚本的加载和执行方式,提高页面的加载性能。一般来说,如果脚本依赖于页面的 DOM
结构或需要在页面加载完毕后执行,推荐使用 defer
属性。如果脚本独立于页面的其他内容,且不依赖于 DOM
结构,可以考虑使用 async
属性(注意执行脚本时会阻塞 HTML
解析)。
总结
需要注意的是,使用这两个属性时,脚本的执行顺序可能会受到影响。如果脚本之间有依赖关系或需要按特定顺序执行,可以考虑将它们放在单独的 <script>
标签中,并使用 defer
属性来确保顺序执行。
而且 defer
和 async
属性只对外部脚本文件(通过 src
属性指定)有效,内联脚本不受这些属性的影响。在使用这些属性时,要根据具体的需求和脚本的依赖关系来选择合适的属性,以优化页面性能和交互体验。
参考资料 & 文章
转载自:https://juejin.cn/post/7241966801214259257