async 和 defer 这俩家伙 到底哪儿不一样?
常见的几种脚本的加载方式,比如:script、async、defer:
<script src='xxx'></script>
<script src='xxx' async></script>
<script src='xxx' defer></script>
相信有不少人只是听过或者通过第三方框架配置过,但并没有实际深入研究过,也一定会有很多疑问:
- 它们的区别到底是啥?
- 会不会阻塞Html的解析?
- 它们各自加载的顺序谁来决定?
- 什么场景下使用哪种方式?
那带着上面这些疑问,我们继续:
script
浏览器解析HTML时,如果遇到script标签,会暂停HTML的解析发起网络请求获取JS脚本,然后让JS引擎执行JS脚本,执行完成后再恢复对HTML的解析,过程如下:
可以看到script的请求和执行阻阻塞了HTML的解析,如果网络请求迟迟得不到响应,浏览器就会出现白屏情况。
async script
当浏览器解析Html时,如果遇到async script会异步请求JS脚本时不会阻塞HTML的解析,但是请求完成后如果HTML的解析还没有完成,就会停止对html的解析执行JS脚本:
但是如果Html已经解析完成则不会出现阻塞情况。
结论:async script有可能会阻塞Html的解析,也有可能不会
如果存在多个async,其执行顺序是不确定的,完全取决于请求完成的先后顺序。
defer script
defer表示延迟,即:也是异步请求获取资源,但是不会阻塞Html的解析,等Html解析完成后才会继续解析JS脚本
如果有多个defer script,其加载顺序取决于在页面中的引入顺序。
总结
| script标签 | JS执行顺序 | 是否阻塞Html的解析 |
|---|---|---|
| script | 取决于Html中的引入顺序 | 阻塞 |
| script async | 取决于网络请求返回的顺序 | 可能阻塞也可能不阻塞 |
| script defer | 取决于Html中的引入顺序 | 不阻塞 |
使用场景
那到底什么场景下该选用哪种加载方式呢?
- 如果每个外部文件不依赖执行的先后顺序,可以使用 async
- 如果一个脚本依赖另一个脚本的执行,可以使用 defer