defer
defer是script标签具备的属性,类似告诉浏览器:不要等待我的下载,干你该干的事儿就好
defer 特性告诉浏览器不要等待它的下载。所以页面正常的处理HTML,构建DOM。
脚本会在“后台下载”,然后等待DOM 解析完成后,脚本才会执行。
Tips:
- 具有
defer属性的脚本,不会阻塞页面加载 - 具有
defer属性的脚本,需要等待页面DOM 解析完成后再执行,但是会在DOMContentLoaded事件之前
具有 defer 特性的脚本保持其相对顺序,就和常规脚本一样
<script src="1.js" defer />
<script src="2.js" defer />
脚本1和脚本2会并行下载,但是即使2在1之前下载完成,2也需要等待1加载完成再执行
async
async 也是script标签具备的属性,异步去加载执行脚本,不会阻塞页面流程(和defer类似)
但是和defer也有些不同点:
- 浏览器不会因为
async的脚本阻塞自己 async的脚本完全独立,彼此之家没有等待关系DOMContentLoaded和async也没有等待关系(可能在async脚本加载前执行,也可能之后)
动态插入脚本
还要一种方式就是动态插入script标签
const script = document.createElement('script')
script.src = '3.js'
document.body.append(script)
默认情况下动态插入的脚本也是异步的,这个其实很好理解,一旦动态插入,至少保证它不需要等别人,也没有人等它。
但你也可以手动加上defer 或者设置 async 为false
preload & prefetch
preload 和 prefetch 都是link标签的属性
<link rel="preload" href="4.js" as="script">
<link rel="prefetch" href="5.js" as="script">
两者控制的是浏览器什么契机去请求加载 script 资源,但是至于具体脚本的执行顺序,只有当遇到script标签加载的也是对应的JS的时候,浏览器才会直接将预先加载的JS执行掉。
preload是告诉浏览器,这些资源我一进页面就要用,优先去给我请求这些资源
prefetch 是在浏览器空闲的时候去请求这些资源
总结:
| 类型 | 顺序 | 所属标签 | DOMContentLoaded |
|---|---|---|---|
| async | 加载顺序 (脚本在代码中的顺序不重要,先加载完的先执行) | script | 彼此独立,没有等待关系 |
| defer | 文档顺序(脚本在代码中写的顺) | script | DOM解析后,DOMContentLoaded 之后 |
| preload | 优先下载,但不涉及到执行(具体执行顺序依赖对应的script的顺序和加载方式) | link | - |
| prefetch | 浏览器空闲时请求下载,但不涉及到执行(具体执行顺序依赖对应的script的顺序和加载方式) | link | - |