浅谈首屏渲染速度及defer和async的异同

背景

随着业务功能的增长,Web App的“身躯”变得愈来愈臃肿,性能优化迫在眉睫,而首当其冲的是首屏渲染速度的问题。前端

正文

咱们经常说起首屏渲染速度,可是鲜有人去给它下一个确切的定义。在个人理解里面,这里面的速度并非指咱们狭义里的速度,而是广义上的。由于咱们没法准确地统计网络传输所通过的物理里程,故不能用v=s/t去计算。那么如何广义法呢?其实,咱们能够将首屏渲染速度等同为首屏渲染时间来理解。能够这么说,从用户在浏览器地址栏敲入一个url到用户看到一个完整的页面,这个过程所花费的时间就是首屏渲染时间。关系到这个首屏渲染时间的长短有不少因素,好比说,DNS解析时间网络传输时间页面渲染时间等等。今天,咱们就挑其中的一个子环节页面渲染来讲说。页面渲染是指从浏览器接收到从服务器返回的HTML文件那一刻算起,到你眼睛看到一个完整页面为止的过程。对于前端开发来讲,作首屏渲染速度的优化每每会选择在页面渲染这个过程发力。经过优化页面渲染过程,咱们能够减小页面处于白屏状态的时间,从而达到必定的首屏渲染速度优化效果。浏览器

上面只是提到了页面渲染的一个很表象的说法。其实页面渲染这个过程包含了一系列的环节,我能够简单地描述为(以下图):解析HTML构建DOM树;解析CSS,构建CSSOM tree;而后将DOM tree和CSSOM tree合并为render tree。再而后使用render tree所提供的数据进行布局(layout),最后是将整个页面绘制(paint)到屏幕上。而今天咱们的话题跟这其中一个环节-HTML解析有关。性能优化

浏览器在解析HTML文档的时候,遇到常规的script标签会停下来,转而去加载所请求的脚本,紧跟着执行加载回来的脚本。换句话说,使用常规script标签去请求外部脚本的话,会阻塞当前的HTML解析。而阻塞当前的HTML解析,就是阻塞整个页面渲染的过程。因此,咱们能够作的就是使得script标签引用外部脚本的时候不要阻塞HTML解析。服务器

为了达到这个目的,咱们一般会采用如下的方案:网络

  • 把常规的script标签放置到</ body>标签前。
  • 给script标签添加defer,async标志位,使它的加载与HTML解析并行进行。

到这里,咱们就引出了咱们今天的两个主角:defer和async。正如上面所说的,添加了这个标志位的script标签都会异步加载脚本。这是它们共同的特性,那么它们之间又有什么不一样的地方呢?异步

它们不一样的地方体如今两个方面:async

  1. 脚本的执行是否是紧跟着加载发生的?
  2. 若是文档中有多个设置了相同标志位的script标签,它们的加载顺序会是如何?

通过查阅资料和亲身实践,咱们能够有如下的结论:布局

对于defer标志位而言:性能

  1. 添加了defer标志位的script标签所加载回来的脚本会在HTML解析完以后,DOMContendLoaded事件发生以前执行。
  2. 若是文档中有多个设置了defer标志位的script标签的话,它们会按照在文档出现的顺序来加载和执行的。

对于async标志位而言:优化

  1. 添加了async标志位的script标签所加载回来的脚本会紧接着就执行了。
  2. 若是文档中有多个设置了async标志位的script标签的话,它们不会按照在文档出现的顺序来加载和执行的,它们都是乱序的主。

从上面两个结论来看,使用了defer和async标志为的script标签所引用的脚本虽然在加载阶段都不会阻塞HTML解析,可是设置了async标志位的script标签仍是会在紧接着的执行阶段阻塞了HTML解析。而且因为它是乱序的主,因此它不能知足各个类库在依赖管理方面的需求。

正所谓一图胜万言。常规script标签,defer标签和async标签的加载和执行过程跟HTML解析过程的关系以下图:

总结

综上所述,经过调整外部脚本的加载和执行次序来优化首屏渲染速度诸多方案中,为script标签添加defer标志位无疑是最优的。

相关文章
相关标签/搜索