您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

Chrome的First Paint

时间:2019-09-10 11:10:13  来源:  作者:

前言

First paint 直译过来的意思就是浏览器第一次渲染(paint),在First paint之前是白屏,在这个时间点之后用户就能看到(部分)页面内容。

所以研究这个First Paint的触发时机对于优化浏览器页面的首屏渲染时间有很重要的作用。

在正题开始之前,先说下浏览器的页面的加载流程(大体过程是这样,并不精确,只是为了帮助理解后面内容):

  1. 浏览器输入url,浏览器发送请求到服务器,服务器将请求的html返回给浏览器。
  2. 浏览器下载完成HTML(Finish Loading HTML)之后,便开始从上到下解析。
  3. 解析的过程中碰到css和js外链(其实HTML的下载也是这个流程)都会执行以下过程:
  4. Send Request:表示给这个外链对应的服务器发送请求
  5. Receive Response: 表示接收响应,这里是表示告诉浏览器可以开始从网络接收数据了
  6. Receive Data:表示开始接收数据
  7. Finish Loading: 表示已经完成下载数据。
  8. Parse Stylesheet/Evaluate(默认情况下js下载完成之后执行Evaluate,css下载完成后会进行Parse Stylesheet)
  9. 所有的css下载完成后Parse Stylesheet然后开始构建CSSOM
  10. DOM(文档对象模型)和 CSSOM(CSS对象模型)会合并生成一个渲染树(Render Tree)
  11. 根据渲染树的内容计算处各个节点在网页中的大小和位置(Layout,可以理解为“刻章”)
  12. 根据Layout绘制内容在浏览器上(Paint,可以理解为“盖章”)。
Chrome的First Paint

 

正题开始

在最新版的Chrome的perfomance中是能直接看到First Paint这个时间点的,为了方便大家测试,我就直接拿谷歌这个示例页面来做演示:

测试页面

用chrome打开上面链接,最好是隐身模式,防止插件乱入影响判断,按F12或者右键检查元素打开控制台先切换到Network选项,勾选禁用缓存(缓存也会影响到判断):

Chrome的First Paint

 

切换到Perfomance,勾选Screenshots并点击红框进行页面分析(会自动停止的,不用点stop):

Chrome的First Paint

 

分析完后可以看到如下结果:

Chrome的First Paint

 

上图中的绿色的线就是当前页面第一次出现内容的时间点,可以将鼠标放到Main上面的Network中绿色的线附近可以看到在他之前页面空白,在他之后就有内容。 除了绿色的线还有蓝色以及红色的线,这里也解释一下:

Chrome的First Paint

 

简单讲一下DOMContentLoaded、load的区别:

  1. DOMContentLoaded是HTML文档(包括CSS、JS)被加载以及解析完成之后触发(即 HTML->DOM的过程完成 )
  2. load则是在页面的其他资源如图片、字体、音频、视频加载完成之后触发
  3. load事件一般在DOMContentLoaded之后才触发(也有可能在它之前哦)

这个时候发现绿色虚线之前有一个浅绿色方块,相应的解释如下:

Chrome的First Paint

 


Chrome的First Paint

 

由图可以得出“浅绿色”代表的是根据CSSOM计算样式并进行布局绘制的过程,这段时间内浏览器做了一下事情:

  1. Recalculate Style:重新计算样式,确定DOM元素的样式规则(定规则)
  2. Layout:根据计算结果进行布局,确定元素的大小和位置(刻章)
  3. Update Layer Tree: 更新渲染层树
  4. Paint: 绘制,根据前面的Layer Tree绘制页面(位置、大小、颜色、边框、阴影等)(盖章)
  5. Composite Layers: 形成层,浏览器按照合理的顺序合并成一个图层然后输出到屏幕(给别人看)
Chrome的First Paint

 

那什么时候开始First paint呢?在浅绿色方块最前面的虚线往前看,发现在灰色虚线之前都会有一个步骤:就是Parse Stylesheet(调研了很多页面都是如此)

Chrome的First Paint

 

所以,First Paint的加载流程应该是这样:

  1. 所有的CSS加载完成
  2. Parse Stylesheet:构建出CSSOM
  3. Recalculate Style:重新计算样式,确定DOM元素的样式规则(定规则)
  4. Layout:根据计算结果进行布局,确定元素的大小和位置(刻章)
  5. Update Layer Tree:更新渲染层树
  6. Paint:绘制,根据前面的Layer Tree绘制页面(位置、大小、颜色、边框、阴影等)(盖章)
  7. Composite Layers:形成层,浏览器按照合理的顺序合并成一个图层然后输出到屏幕(给别人看)

但是现在还只是确定了First Paint的加载流程,也确定了他是在所有CSS执行完Parse Stylesheet之后才会触发,但是这还是不够准确啊,所以我找了一些CSS和JS的外链来测试,模板如下:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <title>Document</title>
 <link href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.css" rel="stylesheet">
 <link href="https://cdn.bootcss.com/jqueryui/1.12.1/jquery-ui.css" rel="stylesheet">
 <script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script>
 <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
 <script src="https://cdn.bootcss.com/react/16.4.0-alpha.0911da3/cjs/react.development.js"></script>
 <script src="https://cdn.bootcss.com/angular.js/2.0.0-beta.17/angular2.js"></script>
</head>
<body>
 <div id='root1'>
 1
 </div>
 <div id='root2'>
 2
 </div>
 <div id='root3'>
 3
 </div>
</body>
</html>

我们通过改变上面模板里的外链顺序来探究:

第一种情况:

Chrome的First Paint

 


Chrome的First Paint

 

发现FP发生在最后(实心的蓝色线是按shift出来的,不是DOMContentLoaded),现在还发现不了什么。

第二种情况:

调换head中CSS和JS外链位置

Chrome的First Paint

 


Chrome的First Paint

 

仍然发现不了什么

第三种情况

把CSS放head,JS放</body>前

Chrome的First Paint

 


Chrome的First Paint

 

发现FP竟然在蓝色和红色虚线前面出现,通过这点可以确定,FP还跟JS外链的位置有关,继续:

第四种情况:

JS外链放head,CSS放</body>前

Chrome的First Paint

 


Chrome的First Paint

 

发现又跟第一二种情况一样了,所以这种用法是不可取的。

第五种情况:

CSS和JS都放</body>前,且CSS紧贴在div后面,JS在CSS后面:

Chrome的First Paint

 


Chrome的First Paint

 

可以发现FP居然更快触发,但是我鼠标hover到绿色虚线后,仍然是白屏,只有等到CSS加载完成执行Parse Stylesheet之后才显示出内容(说明这种用法也不可取),难道body中的CSS也会影响?

第六种情况:

掉换一下上面CSS和JS的位置:

Chrome的First Paint

 


Chrome的First Paint

 

发现这次FP触发而且立马有内容,而等到CSS加载完成之后还会再重新渲染一次,嗯,看来body中的第一个JS脚本有猫腻,接下来的情况对他特殊照顾。

第七种情况:

CSS放head中,JS放在div节点中间:

Chrome的First Paint

 


Chrome的First Paint

 

哈哈,居然只渲染了12俩字,说明浏览器会渲染body中脚本之前的内容,那会是哪个脚本之前的内容呢?

第八种情况:

在div之间都插入脚本

Chrome的First Paint

 


Chrome的First Paint

 

看来浏览器会提前渲染body中第一个脚本前的内容(我们就把body中的第一个外链脚本叫做【第一脚本】吧),并且第一脚本还会在FP之后才执行。所以结合之前得出的结论,在CSSOM准备就绪之后,浏览器会提前渲染第一脚本前的内容,我们可以用第九种情况来验证:

第九种情况:

这种情况和上种没什么区别,只是增加了一个CSS,这个CSS中还会发出一个请求去加载其他CSS(通过@import url()的方式),所以CSS的加载时间很长。

Chrome的First Paint

 


Chrome的First Paint

 

通过结果可以看出,123在CSS下载完成之后才渲染,而不是单独渲染一个1,所以FP必须得等到CSSOM准备就绪之后才会触发,否则即使有第一脚本在也没用。 所以到这里,我们总算可以下结论了:

FP发生在body中第一个script脚本之前的CSS解析和JS执行完成之后。换句话说就是第一脚本之前的DOM和CSSOM准备就绪之后,便会着手渲染第一脚本前的内容。

但是...你以为到这里就结束了?其实没有。

第十种情况:

这种情况中,head中既有JS也有CSS,body中也有第一脚本存在:

Chrome的First Paint

 


Chrome的First Paint

 

注意上图中的vue.js是在head中的,而后面的JS文件都在body中,而且,vue.js加载完成之后,body中的JS还没下载完成,这个时候我们调换一下vue.js和angular2.js的位置:

Chrome的First Paint

 


Chrome的First Paint

 

看,这个时候又没有提前渲染了,123等到所有JS文件都执行完之后才渲染,这种情况除了验证了第九点的结论,还能补充我们的结论:

如果第一脚本前的JS和CSS加载完了,body中的脚本还未下载完成,那么浏览器就会利用构建好的局部CSSOM和DOM提前渲染第一脚本前的内容(触发FP);如果第一脚本前的JS和CSS都还没下载完成,body中的脚本就已经下载完了,那么浏览器就会在所有JS脚本都执行完之后才触发FP。

到这里本次探究就结束了,其实还有很多种情况,感兴趣的可以自己去试试。

建议:

  • CSS放在head中,JS放在</body>前(如果在head必须放JS,也尽量减少他的大小,把大JS文件放</body>前)。
  • 减小head中CSS和JS大小(gzip了解一下?),
  • 优化head中的JS和CSS外链的网络情况,减少Stalled、TTFB和Content Download的时间。
  • 在第一脚本前使用骨架图,可以减少用户的白屏感知时间(对于使用JS插入模板来渲染的框架,建议将骨架图的路由生成逻辑单独提出来)

科普一下

  • Chrome会渲染局部CSSOM和DOM
  • First Paint和DOMContentLoaded、load事件的触发没有绝对的关系,FP可能在他们之前,也可能在他们之后,这取决于影响他们触发的因素的各自时间(FP:第一脚本前CSSOM和DOM的构建速度;DOMContentLoaded:HTML文档自身以及HTML文档中所有JS、CSS的加载速度;load:图片、音频、视频、字体的加载速度)。
  • DOMContentLoaded和load事件也没有强制的先后顺序,DOMContentLoaded一般在load事件之前触发,但也可能在load事件之后触发。
  • 第一脚本前的CSS如果还会去加载字体文件,那么即使CSSOM和DOM构建完成触发FP,页面内容也会是空白,只有等到字体文件下载完成才会出现内容(这也是我们在打开一个加载了谷歌字体的网站会白屏很长时间的原因)。
  • 默认情况下,CSS外链之间是谁先加载完成谁先解析,但是JS外链之间即使先加载完成,也得按顺序执行。
  • link外链后面紧跟script外链,须先等link parse完成之后,script才会执行,即使script先下载完成。script后面紧跟link,也是一样,会等script执行完之后,link才会parse。
  • 如果script之后紧跟几个link且script比这几个link的下载时间都长,那script执行完成之后link是按顺序执行。
  • RRDL:
  • R:send Request,发送资源请求
  • R:receive Response,接收到服务端响应
  • D:receive Data,开始接受服务端数据(一个资源可能执行多次)
  • L:finish Loading,完成资源下载
  • 浏览器在RRDL的时候,在D(Receive data)这个步骤可能执行多次。
  • TTFB:Time To First Byte,第一个字节返回的时间,这个是对应send Request到receive Response这段时间。
  • 浏览器会给HTML中的资源文件进行等级分类(Hightest/High/Meduim/Low/Lowest),一般HTML文档自身、head中的CSS都是Hightest,head中JS一般是High,而图片一般是Low,而设置了async/defer的脚本一般是Low,gif图片一般是Lowest。
  • 下图中的资源文件浅色和深色和第二个图画红框的位置是对应的(不信自己计算一下对应的时间)
Chrome的First Paint

 


Chrome的First Paint

 

希望本文能帮助到您!

点赞+转发,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓-_-)

关注 {我},享受文章首发体验!

每周重点攻克一个前端技术难点。更多精彩前端内容私信 我 回复“教程”

原文链接:http://eux.baidu.com/blog/fe/Chrome%E7%9A%84First%20Paint

作者:洪闰辉



Tags:Chrome First Paint   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
First paint 直译过来的意思就是浏览器第一次渲染(paint),在First paint之前是白屏,在这个时间点之后用户就能看到(部分)页面内容。...【详细内容】
2019-09-10  Tags: Chrome First Paint  点击:(173)  评论:(0)  加入收藏
▌简易百科推荐
本文分为三个等级自顶向下地分析了glibc中内存分配与回收的过程。本文不过度关注细节,因此只是分别从arena层次、bin层次、chunk层次进行图解,而不涉及有关指针的具体操作。前...【详细内容】
2021-12-28  linux技术栈    Tags:glibc   点击:(3)  评论:(0)  加入收藏
摘 要 (OF作品展示)OF之前介绍了用python实现数据可视化、数据分析及一些小项目,但基本都是后端的知识。想要做一个好看的可视化大屏,我们还要学一些前端的知识(vue),网上有很多比...【详细内容】
2021-12-27  项目与数据管理    Tags:Vue   点击:(2)  评论:(0)  加入收藏
程序是如何被执行的&emsp;&emsp;程序是如何被执行的?许多开发者可能也没法回答这个问题,大多数人更注重的是如何编写程序,却不会太注意编写好的程序是如何被运行,这并不是一个好...【详细内容】
2021-12-23  IT学习日记    Tags:程序   点击:(9)  评论:(0)  加入收藏
阅读收获✔️1. 了解单点登录实现原理✔️2. 掌握快速使用xxl-sso接入单点登录功能一、早期的多系统登录解决方案 单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器...【详细内容】
2021-12-23  程序yuan    Tags:单点登录(   点击:(8)  评论:(0)  加入收藏
下载Eclipse RCP IDE如果你电脑上还没有安装Eclipse,那么请到这里下载对应版本的软件进行安装。具体的安装步骤就不在这赘述了。创建第一个标准Eclipse RCP应用(总共分为六步)1...【详细内容】
2021-12-22  阿福ChrisYuan    Tags:RCP应用   点击:(7)  评论:(0)  加入收藏
今天想简单聊一聊 Token 的 Value Capture,就是币的价值问题。首先说明啊,这个话题包含的内容非常之光,Token 的经济学设计也可以包含诸多问题,所以几乎不可能把这个问题说的清...【详细内容】
2021-12-21  唐少华TSH    Tags:Token   点击:(10)  评论:(0)  加入收藏
实现效果:假如有10条数据,分组展示,默认在当前页面展示4个,点击换一批,从第5个开始继续展示,到最后一组,再重新返回到第一组 data() { return { qList: [], //处理后...【详细内容】
2021-12-17  Mason程    Tags:VUE   点击:(14)  评论:(0)  加入收藏
什么是性能调优?(what) 为什么需要性能调优?(why) 什么时候需要性能调优?(when) 什么地方需要性能调优?(where) 什么时候来进行性能调优?(who) 怎么样进行性能调优?(How) 硬件配...【详细内容】
2021-12-16  软件测试小p    Tags:性能调优   点击:(20)  评论:(0)  加入收藏
Tasker 是一款适用于 Android 设备的高级自动化应用,它可以通过脚本让重复性的操作自动运行,提高效率。 不知道从哪里听说的抖音 app 会导致 OLED 屏幕烧屏。于是就现学现卖,自...【详细内容】
2021-12-15  ITBang    Tags:抖音防烧屏   点击:(25)  评论:(0)  加入收藏
11 月 23 日,Rust Moderation Team(审核团队)在 GitHub 上发布了辞职公告,即刻生效。根据公告,审核团队集体辞职是为了抗议 Rust 核心团队(Core team)在执行社区行为准则和标准上...【详细内容】
2021-12-15  InfoQ    Tags:Rust   点击:(25)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条