Chrome的First Paint
前言
First paint 直译过来的意思就是浏览器第一次渲染(paint),在First paint之前是白屏,在这个时间点之后用户就能看到(部分)页面内容。
所以研究这个First Paint的触发时机对于优化浏览器页面的首屏渲染时间有很重要的作用。
在正题开始之前,先说下浏览器的页面的加载流程(大体过程是这样,并不精确,只是为了帮助理解后面内容):
- 浏览器输入url,浏览器发送请求到服务器,服务器将请求的HTML返回给浏览器。
- 浏览器下载完成HTML(Finish Loading HTML)之后,便开始从上到下解析。
- 解析的过程中碰到css和js外链(其实HTML的下载也是这个流程)都会执行以下过程:
Send Request
:表示给这个外链对应的服务器发送请求Receive Response
: 表示接收响应,这里是表示告诉浏览器可以开始从网络接收数据了Receive Data
:表示开始接收数据Finish Loading
: 表示已经完成下载数据。Parse Stylesheet/Evaluate
(默认情况下js下载完成之后执行Evaluate
,css下载完成后会进行Parse Stylesheet
)
- 所有的css下载完成后
Parse Stylesheet
然后开始构建CSSOM - DOM(文档对象模型)和 CSSOM(CSS对象模型)会合并生成一个渲染树(
Render Tree
) - 根据渲染树的内容计算处各个节点在网页中的大小和位置(
Layout
,可以理解为“刻章”) - 根据Layout绘制内容在浏览器上(
Paint
,可以理解为“盖章”)。
正题开始
在最新版的Chrome的perfomance
中是能直接看到First Paint这个时间点的,为了方便大家测试,我就直接拿谷歌这个示例页面来做演示:
用chrome打开上面链接,最好是隐身模式,防止插件乱入影响判断,按F12或者右键检查元素打开控制台先切换到Network
选项,勾选禁用缓存(缓存也会影响到判断):
切换到Perfomance
,勾选Screenshots
并点击红框进行页面分析(会自动停止的,不用点stop):
分析完后可以看到如下结果:
上图中的绿色的线就是当前页面第一次出现内容的时间点,可以将鼠标放到Main
上面的Network
中绿色的线附近可以看到在他之前页面空白,在他之后就有内容。
除了绿色的线还有蓝色以及红色的线,这里也解释一下:
简单讲一下DOMContentLoaded
、load
的区别:
DOMContentLoaded
是HTML文档(包括CSS、JS)被加载以及解析完成之后触发(即HTML->DOM
的过程完成 )load
则是在页面的其他资源如图片、字体、音频、视频加载完成之后触发load
事件一般在DOMContentLoaded
之后才触发(也有可能在它之前哦)
这个时候发现绿色虚线之前有一个浅绿色方块,相应的解释如下:
由图可以得出“浅绿色”代表的是根据CSSOM计算样式并进行布局绘制的过程,这段时间内浏览器做了一下事情:
Recalculate Style
:重新计算样式,确定DOM元素的样式规则(定规则)Layout
:根据计算结果进行布局,确定元素的大小和位置(刻章)Update Layer Tree
: 更新渲染层树Paint
: 绘制,根据前面的Layer Tree绘制页面(位置、大小、颜色、边框、阴影等)(盖章)Composite Layers
: 形成层,浏览器按照合理的顺序合并成一个图层然后输出到屏幕(给别人看)
那什么时候开始First paint
呢?在浅绿色方块最前面的虚线往前看,发现在灰色虚线之前都会有一个步骤:就是Parse Stylesheet
(调研了很多页面都是如此)
所以,First Paint的加载流程应该是这样:
- 所有的CSS加载完成
Parse Stylesheet
:构建出CSSOMRecalculate Style
:重新计算样式,确定DOM元素的样式规则(定规则)Layout
:根据计算结果进行布局,确定元素的大小和位置(刻章)Update Layer Tree
:更新渲染层树Paint
:绘制,根据前面的Layer Tree绘制页面(位置、大小、颜色、边框、阴影等)(盖章)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>
我们通过改变上面模板里的外链顺序来探究:
第一种情况:
发现FP发生在最后(实心的蓝色线是按shift
出来的,不是DOMContentLoaded
),现在还发现不了什么。
第二种情况:
调换head
中CSS和JS外链位置
仍然发现不了什么
第三种情况
把CSS放head
,JS放</body>
前
发现FP
竟然在蓝色和红色虚线前面出现,通过这点可以确定,FP
还跟JS外链的位置有关,继续:
第四种情况:
JS外链放head
,CSS放</body>
前
发现又跟第一二种情况一样了,所以这种用法是不可取的。
第五种情况:
CSS和JS都放</body>
前,且CSS紧贴在div
后面,JS在CSS后面:
可以发现FP
居然更快触发,但是我鼠标hover到绿色虚线后,仍然是白屏,只有等到CSS加载完成执行Parse Stylesheet
之后才显示出内容(说明这种用法也不可取),难道body中的CSS也会影响?
第六种情况:
掉换一下上面CSS和JS的位置:
发现这次FP
触发而且立马有内容,而等到CSS加载完成之后还会再重新渲染一次,嗯,看来body中的第一个JS脚本有猫腻,接下来的情况对他特殊照顾。
第七种情况:
CSS放head
中,JS放在div
节点中间:
哈哈,居然只渲染了12俩字,说明浏览器会渲染body中脚本之前的内容,那会是哪个脚本之前的内容呢?
第八种情况:
在div之间都插入脚本
看来浏览器会提前渲染body
中第一个脚本前的内容(我们就把body中的第一个外链脚本叫做【第一脚本】吧
),并且第一脚本还会在FP之后才执行。所以结合之前得出的结论,在CSSOM准备就绪之后,浏览器会提前渲染第一脚本前的内容,我们可以用第九种情况来验证:
第九种情况:
这种情况和上种没什么区别,只是增加了一个CSS,这个CSS中还会发出一个请求去加载其他CSS(通过@import url()
的方式),所以CSS的加载时间很长。
通过结果可以看出,123在CSS下载完成之后才渲染,而不是单独渲染一个1,所以FP
必须得等到CSSOM
准备就绪之后才会触发,否则即使有第一脚本在也没用。
所以到这里,我们总算可以下结论了:
FP发生在body中第一个script脚本之前的CSS解析和JS执行完成之后。换句话说就是第一脚本之前的
DOM
和CSSOM
准备就绪之后,便会着手渲染第一脚本前的内容。
但是...你以为到这里就结束了?其实没有。
第十种情况:
这种情况中,head
中既有JS也有CSS,body
中也有第一脚本存在:
注意上图中的vue.js
是在head
中的,而后面的JS文件都在body
中,而且,vue.js
加载完成之后,body
中的JS还没下载完成,这个时候我们调换一下vue.js
和angular2.js
的位置:
看,这个时候又没有提前渲染了,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
。 - 下图中的资源文件浅色和深色和第二个图画红框的位置是对应的(不信自己计算一下对应的时间)
参考链接:
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3akuvl3965mok
Chrome的First Paint的更多相关文章
- css属性的选择对动画性能的影响
现在手机的占比越来越高,各种酷炫页面层出不穷,这些特效都离不开css动画.说到css动画,主流的情况也就无非这两大类:位移和形变.而我们在写一个动画特效的过程中,如何去提升它的性能呢?当然首先我们需要 ...
- Chrome 开发工具之Timeline
之前有说到Element,Console,Sources大多运用于debug,Network可用于debug和查看性能,今天的主角Timeline更多的是用在性能优化方面,它的作用就是记录与分析应用程 ...
- 如何使用Chrome Timeline 工具(译)
[原文地址]https://developers.google.com/web/tools/chrome-devtools/profile/evaluate-performance/timeline- ...
- Chrome开发者工具详解(3)-Timeline面板
Chrome开发者工具详解(3)-Timeline面板 注: 这一篇主要讲解面板Timeline,参考了Google的相关文档,主要用于公司内部技术分享.. Timeline面板 Timeline面板 ...
- 使用Chrome工具来分析页面的绘制状态
Chrome Canary(Chrome “金丝雀版本”)目前已经支持Continuous painting mode,用于分析页面性能.这篇文章将会介绍怎么才能页面在绘制过程中找到问题和怎么利用这个 ...
- 使用Chrome DevTools的Timeline分析页面性能
随着webpage可以承载的表现形式更加多样化,通过webpage来实现更多交互功能,构建web应用程序已经成为很多产品的首要选择.这种方式拥有非常明显的优势:跨平台.开发便捷.便于部署和维护等等,但 ...
- 当fixed元素相互嵌套时chrome下父元素会影响子元素的层叠关系
问题:fixed元素被另一个fixed元素包含的时候在chrome下fixed子元素的定位会受到父元素的影响. demo(http://jsbin.com/qumah/1): <!DOCTYPE ...
- Chrome渲染分析之Timeline工具的使用
原文http://www.th7.cn/web/html-css/201406/42043.shtml Timeline工具栏提供了对于在装载你的Web应用的过程中,时间花费情况的概览,这些应用包括处 ...
- 使用Chrome DevTools的Timeline和Profiles提高Web应用程序的性能
来源: http://www.oschina.net/translate/performance-optimisation-with-timeline-profiles 我们都希望创建高性能的Web应 ...
随机推荐
- python小练习之一
下面的练习本身不难,比如打印1到10,计算1+2+3+...+100 ,最后一个是计算 1-2+3-4...-100 用了类的方法实现 用了列表生成器 用"高级"一丢丢的写法来实现 ...
- PHP trait
ps:由于PHP是单继承的,无法继承多个类所以可以用triat(关键字,特性)来命名达到子类继承多个父类的效果:暂且理解为类吧.class = trait <?php trait A { pub ...
- Echarts 折线图y轴标签值太长时显示不全的解决办法
问题 分析 解决办法 问题 先看一下正常的情况 再看一下显示不全的情况 所有的数据都是从后台取的,也就是说动态变化的,一开始的时候数据量不大不会出现问题,后面y轴的值越来越大的时候就出现了这个显示不全 ...
- ELK学习总结(4-1)elasticsearch更改mapping(不停服务重建索引)
elasticsearch更改mapping(不停服务重建索引)原文 http://donlianli.iteye.com/blog/1924721Elasticsearch的mapping一旦创建, ...
- Python之IO模型
IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞 ...
- 详解k8s零停机滚动发布微服务 - kubernetes
1.前言 在当下微服务架构盛行的时代,用户希望应用程序时时刻刻都是可用,为了满足不断变化的新业务,需要不断升级更新应用程序,有时可能需要频繁的发布版本.实现"零停机"." ...
- 阿里云下Linux服务器安装Mysql、mongodb
阿里云下Linux服务器安装Mysql.mongodb 一.MySQL的安装和配置 1.安装rpm包 rpm -Uvh http://dev.mysql.com/get/mysql-community ...
- shell:bash环境
1.什么是shell shell一般代表两个层面的意思,一个是命令解释器,比如BASH,另外一个是shell脚本. 命令解释器shell的发展史,sh-csh-ksh-tcsh-bash. 2.命令的 ...
- zoj 3950 how many nines
https://vjudge.net/problem/ZOJ-3950 题意: 给出两个日期,计算从第一个日期开始到第二个日期,每一天的日期中的9加起来一共有多少个. 思路: 看题解补的题.首先看这题 ...
- geotrellis使用(三十七)COG 基础介绍
前言 Geotrellis 已经迭代到了 2.0 版本(截止写作此文时为 2.0.0-SNAPSHOT 版),2.0 版多了很多新的特性,其中最重要的应该就是 COG,COG 是什么鬼?刚看到时我也是 ...