前端性能优化 - 外部js和css加载对页面渲染首屏的影响

写在开头,本文中的内容均为自己测试得到的结果,如有不正之处,还望指出!

开始今天的学习之前,先看一个概念。“页面渲染首屏”指的是什么?

首先我们要明确这个概念。首先给大家看一个图片(百度搜索引擎的页面的加载过程):


火焰图模块可以看到三条竖的虚线
蓝线代表DOM生成完毕,对应DOMContentLoaded event,
绿线代表第一次绘制的时间,
红色代表加载完成,对应load事件。

那么我们所说的是什么呢?我这里认为的是绿色线,然后我们再看一下绿色线页面渲染情况?


图中红色标注的原先是绿线,因为我鼠标放在上面的问题,变成了蓝色。我们现在看到的是就是没有百度大logo的样式(与图中左侧相比)。今天的主要是学习一些js和css的外部加载会对这个首屏加载时间有什么样的影响。(所有的测试基于chorme)

1. 外部js&css-script标签在head中

下面的例子可以访问外部js&css-script标签在head中,至于js文件和css文件就不贴出来了,可以再给的link中查看,css很简单,js是jquery文件。

<!Doctye html>
<html>
<head>
  <link rel='stylesheet' href='./style.css' type='text/css'/>
  <script type='text/javascript' src='./index.js'></script>
</head>
<body>
  <div class='div'> 
    Test dom load.
  </div>
</body>
</html>
还是和之前一样先贴出来performence中页面渲染的过程,由于图片比较大,可以点击图片放大查看。


图中有三个红色的圆框

第一个红色框
这里第一个主要是发送请求当前页面的请求以及拿到数据,具体的过程前面的文章已经说过了,这里就不一一在图中表明了。最后的step是一个p字母开头的蓝色区域,这里是parsehtml,也就是对于当前的页面解析,html的解析过程由上而下,解析到style标签是一个外部资源,于是发送请求css文件(图中parsehtml下方第一条竖线),继续解析到script同样也是外部资源,同样发送请求外部js文件(图中parsehtml下方第二条竖线)。

第二个红色框
是关于外部js&css的请求。

第三个红色框
第三个红色框的内容首先是加载执行js代码,然后才是构建构建DOM成功,接着是渲染页面,可以看到图中的绿色竖线已经是在最后面了,就是现在js(head内部)代码已经影响到页面渲染首屏的时间。


这里扯个闲篇

css的加载不会阻塞html的页面解析,因为如果阻塞的话,就不会在css资源还没有处理完的情况下,继续解析到script的标签。

那么对于js代码的执行会不会进行阻塞呢?
答案是会阻塞后面的js文件,为什么呢?这个呢其实可以看图中的第二个红色的圆框内,是关于请求外部资源js和css的,可以看到第三个圆框内的加载js代码是在第二个红色圆框的后面。js的加载执行是在css请求之后进行的。css的外部资源是会影响后面js代码的执行。

那么对于DOM树的构建呢?注意这里说的是DOM树的构建,答案请看本文第二章节。

对于Render的渲染肯定是会有阻塞的,因为Render树的构建需要CSSOM。


2. 外部js&css-script标签在body的结尾

下面的例子可以访问 外部js&css-script标签在body的结尾

<!Doctye html>
<html>
<head>
  <link rel='stylesheet' href='./style.css' type='text/css'/>
</head>
<body>
  <div class='div'> 
    Test dom load.
  </div>
  <script type='text/javascript' src='./index.js'></script>
</body>
</html>
同样把页面的performance过程贴出来

图中有三个红色框(第四个属于第二个红色框)。
第一个红色框
和上面的相同,就不在赘述。

第二个红色框
首先是进行css文件的加载,然后是进行Recalculate Style,Layout,Update Layer Tree,Paint,Composite Layers,进而渲染页面首屏,同样我们也看到了绿色竖线。

这里得到的结果是:位于body尾部的js外部文件不会对页面的首屏渲染进行影响,因为js的文件还没有加载。还在第三个红色框内部。

第三个红色框
加载执行js文件,并且重新计算样式,进行页面的渲染(这里的渲染应该是局部渲染,具体的内容还是需要到后面去学习,本章主要的内容还是在渲染首屏)。

同样扯个闲篇:

对于上面遗留的问题:css的加载会不会影响到DOM树的构建,这里我的理解是不会(可能出错,本人只是按照自己的想法说的)。因为从上面的图中看到,在第二个红色框内没有parseHtml的蓝色区域,如果有影响的话,这里应该会有一段蓝色区域去构建DOM树。当然如果chrome performence没有将构建DOM树的过程体现在火焰图中的,那就另当别论了。


3. 结论

从上面的两个例子看到的结果:
css的加载会对页面渲染首屏进行阻塞
js代码(位于head中)会对页面渲染首屏有阻塞,但是位于body标签最后的不会对于渲染首屏进行阻塞。当然,如果加载的js在css返回之前返回,那么js代码的执行会在渲染首屏之前进行执行,会对渲染首屏有阻塞


4. 闲篇defer & async

还是先回到上面的两个例子中去,最好可以点击到我给里的link中亲自去查看,会发现DOMContentLoad的时间都是在js执行之后才会执行的。

然后我们先看一下关于defer和async的介绍:

(1) 默认引用 script:<script type="text/javascript" src="x.min.js"></script>
当浏览器遇到 script 标签时,文档的解析将停止,并立即下载并执行脚本,脚本执行完毕后将继续解析文档。

(2) async模式 <script type="text/javascript" src="x.min.js" async></script>
当浏览器遇到 script 标签时,文档的解析不会停止,其他线程将下载脚本,脚本下载完成后开始执行脚本,脚本执行的过程中文档将停止解析,直到脚本执行完毕。

(3) defer模式 <script type="text/javascript" src="x.min.js" defer></script>
当浏览器遇到 script 标签时,文档的解析不会停止,其他线程将下载脚本,待到文档解析完成,脚本才会执行。

这里由于今天时间的关系,就不贴出图片了,具体的页面变化可以访问linkdefer,async,这里只是说当js在head标签内的情况。

这里就只说我看到的结果

当head内部js是async的时候,渲染页面首屏的时间会和将js放在body尾部的情况大致相同,不同的是DOMContentLoad的执行时间,可以看到DOMContentLoad执行的时间不在依赖于js脚本的执行是否完成,而是只依赖于DOM树的构建。如果是defer的情况下,会看到渲染初始首屏同样也不会依赖于js脚本的执行,但是和async不同的是DOMContentLoad的执行时间还是在js执行完成之后。

这二者之间的区别

js文件是否依赖于别人,如果依赖于别人,则可以使用defer,因为defer更符合我们的实际需求。对于async,个人其实没有想到用它的必要条件。主要原因是因为defer的执行按照在html自上而下的顺序执行的,但是async去不一定按照顺序执行。

猜你喜欢

转载自blog.csdn.net/it_rod/article/details/79703635