《重学JavaScript系列专栏》async 和 defer 这俩家伙 到底哪儿不一样?

638 阅读3分钟

常见的几种脚本的加载方式,比如: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的解析,过程如下:

image.png

可以看到script的请求执行阻阻塞了HTML的解析,如果网络请求迟迟得不到响应,浏览器就会出现白屏情况

async script

当浏览器解析Html时,如果遇到async script会异步请求JS脚本时不会阻塞HTML的解析,但是请求完成后如果HTML的解析还没有完成,就会停止对html的解析执行JS脚本:

image.png

但是如果Html已经解析完成则不会出现阻塞情况。

image.png

结论:async script有可能会阻塞Html的解析,也有可能不会

比如antd官网,就有很多资源是通过async script加载的。

image.png

如果存在多个async,其执行顺序是不确定的,完全取决于请求完成的先后顺序

defer script

defer表示延迟,即:也是异步请求获取资源,但是不会阻塞Html的解析,等Html解析完成后才会继续解析JS脚本

image.png

可以看到掘金就使用了很多defer script加载JS

image.png 如果有多个defer script,其加载顺序取决于在页面中的引入顺序

总结

script标签JS执行顺序是否阻塞Html的解析
script取决于Html中的引入顺序阻塞
script async取决于网络请求返回的顺序可能阻塞也可能不阻塞
script defer取决于Html中的引入顺序不阻塞

使用场景

那到底什么场景下该选用哪种加载方式呢?

  • 如果每个外部文件不依赖执行的先后顺序,可以使用 async
  • 如果一个脚本依赖另一个脚本的执行,可以使用 defer

浏览器兼容性

《重学JavaScript系列专栏》其它文章推荐:

《手撕源码系列专栏》文章推荐

《Webpack配置从基础到高阶系列专栏》文章推荐

参考文章: async vs defer attributes