首先提出一个问题:script标签在body或head中会影响阻塞吗?
答案:默认script是同步执行,会发生阻塞。JS脚本存在,会阻塞DOM渲染从而影响页面渲染速度
原因:
- 浏览器解析html时,从上往下执行
- 解析到DOM中的script时,会暂停DOM构建
- 脚本加载并执行完成后,才会继续往下解析
<script src="xxx.js?wait=1000"></script>
async script
<script async="async" src="xxx.js?wait=1000"></script>
async实现异步执行,可以理解是EventLoop中的宏任务。
当浏览器遇到async script时,会执行异步请求脚本,不会阻塞浏览器解析HTML。
- 一旦网络请求回来之后,如果HTML还没有解析完,浏览器会暂停解析,先让JS引擎执行代码,执行完毕后再继续解析
- 如果JS脚本请求之前,HTML解析完毕,立即执行JS
所以async是不可控的,因为执行时间无法确定
- 如果JS脚本中需要获取某个DOM元素,可能获取不到
- 如果存在多个async script时,他们之间的执行顺序也不确定,谁先到谁执行
defer script
<script defer="defer" src="xxx.js?wait=1000"></script>
defer同样是延迟加载的意思,不会阻塞浏览器解析HTML
一旦网络请求回来后
- 如果此时HTML还没有解析完,浏览器不会暂停解析并执行JS代码,而是等待
HTML解析完毕后再执行JS
如果存在多个defer script标签,浏览器会保证按照在HTML中出现的顺序执行,不会破坏JS脚本之间的依赖关系
比较
| script标签 | 执行顺序 | 是否阻塞解析HTML |
|---|---|---|
| script | 在HTML中的顺序 | 会阻塞 |
| async script | 网络请求返回顺序 | 可能阻塞,可能不阻塞 |
| defer script | HTML中的顺序 | 不阻塞 |
其他
webpack打包后,html页面中的script使用的是defer