内容
- 浏览器渲染原理
- 资源对渲染的影响
- 优化关键渲染路径
浏览器渲染原理
DOM
Timeline
录制时需注意
- 禁用缓存,以便测试首次浏览性能
- 关闭Chrome 扩展 或使用隐身模式
模式真实网络情况
Chrome Canary
总结TImeline
1:控制条
- 开始记录, 停止记录
- 配置记录期间捕获的信息
2: 总揽
- 页面性能高级汇总
3:火焰图
- CPU 堆叠追踪的可视化
4:详情
- 每个CPU 任务的详细报告
增量构建
浏览器无需等待html 加载完毕,便可开始解析DOM
自己动手
使用 performance 工具 分析自己常逛的网站。找到主线程中构建DOM所在的步骤
总结
描述浏览器是如何构建DOM的
CSSOM
RenderTree
- RenderTree 包含了渲染网页所需要的节点
- 无需渲染的节点不会被添加到RenderTree中。
思考Lvisitilty:hidden 的节点,是否会被添加到RenderTree?
Recalculate Style : 构建 RenderTree
Layout :计算渲染书节点的位置和大小
Viewport
- device-width 为浏览器的理想视口
- 在移动端 ,如果不设置viewpost 宽度为理想视口,viewport宽度通常为,980px,这会导致文字很小,我们需要手动放大阅读
思考 :
哪些操作会触发Layout
- 屏幕旋转
- 浏览器视口改变
- 与大小位置相关的css属性改变
https://csstriggers.com/
总结
试着画出浏览器渲染过程
并描述每一步执行的工作
构建DOM
- 构建过程
character token node DOM - 增量构建
构建CSSOM
- 构建过程
charactor token node CSSOM - 选择器越复杂,匹配用的时间越多
构建RenderTree
- RenderTree 包含所有需要呈现在页面上的节点信息
- display:none 的元素不会被添加到RenderTree 汇总,因为不需要本渲染
- visibility:hidden 的元素会被添加到RenderTree中,因为它虽然不可见,但是会占有位子
Layout
- 计算需要渲染的节点的大小和位置
- 节点位置和大小是给予viewport计算的
- 在移动端通常将viewport设为浏览器推荐的理想适口,以保证字体显示大小易于阅读
- 旋转屏幕,修改浏览器大小,修改位置大小相关的css属性都有可能触发Layout
Paint
- 根基background,border, box-shadow等样式,将Layout生成区域填充为最终将显示在屏幕上的像素
资源对渲染的影响
资源
- css
- js
- font
- img
思考
浏览器会在何时渲染页面
- 加载完DOM立即开始渲染
- 加载完DOM和CSSOM
css阻塞初次渲染(有待测试)
‘index.css’>
- 通过以上两种方式定义css,均会阻塞初次渲染
- 浏览器会在解析完css后,再进行渲染,这是为了防止样式突变带来饿抖动
- 不管css 出现文档中的那个位置,都会阻塞整个文档的初次渲染
- 通过link 标签引入的css阻塞的时间可能更长,因为加载它需要一个网络来回时间
dedia query
<link rel='sty;esheet' href='index_print.css' media='print'>
- 此样式表仍会加载
- 当浏览器环境不匹配媒体查询时,改样式表不会阻塞渲染
- 我们可针对不同媒体环境拆分css文件,并为link标签添加媒体查询,避免为了加载非关键css资源,而阻塞初次渲染。
通过documnt.write 添加link
<script>
document.write('<link ref='stylesheet' href='inex.css' />')
</script>
通过DOM API 添加link
var style = document.createElement(‘link’)
style.rel = ‘stylesheet’;
style.href = ‘index.css’;
document.head.appendChild(style)
不会阻塞初次渲染
preload
<link / rel='preloa' href='index_print.css' as=style onloa='this.rel=stylesheet'>
- fel 不是stylesheet,因此不会阻塞渲染
- preloa 是resoure hint 规范中定义中一个功能
- resource hint 通过告知浏览器提前 建立链接或加载资源,以提高资源加载的速度
- 浏览器遇到标记为preloa的link 时,会开始加载它
- 当onload 时间发生时,将rel改为stylesheet 即可应用此样式
loadCSS.js
- CSS preload polyfill
- 让我们可以使用preloa 语法异步加载css
- 原理是通过DOM API 插入样式资源
思考
<body>
<p>hello</p>
// 这个脚本会加载10秒左右
<script src='slowscript.js'></script>
<p>world</p>
</body>
//显示情况是 立即显示hello 10秒后显示world
javascript 阻塞HTML parser
// inline js
<script> </script>
// external js
<script src='somescript'></script>
- 通过以上两种方式引入js脚本均会阻塞html parser,因而会阻塞出现在脚本后面的HTML 标记的渲染
- 外部script 阻塞时间一般更长,以为可能包含了一个网络来回时间
- javascript 可以通过document.write 修改HTML 文档流,因此在执行js时, 浏览器会暂停解析DOM的工作
<html>
<head>
//p {color: green}
<link rel='stylesheet' href = 'index.css'>
</head>
<body>
<p>hello wrold</p>
<script>
let p = document.querySelector('p');
let color = window.getComputedStyle(p).color
console.log(color)
</script>
</body>
</html>
//如果HTML Parse 解析到<script></script> 标签时,样式仍未加载完成,会发生什么? 最后打印的颜色是多少?
CSS阻塞JS
//inline js
<script> //app logics here <script>
//external js
<script src='somescript.js'></script>
- 通过以上两种方式引入的JS均会被CSS 阻塞
- 由于这些javascript 可能会读取或修改CSSOM,因此需要等待CSSOM 构造完成后,它们才会执行
<html>
<head>
<script src='index.js'></script>
<script> src='tongji.js' </script>
</head>
<body>
</body>
</html>
//这两个js文件浏览器会同时加载
Preloa
- 当HTML parse 被脚本阻塞时,Parser 虽然停止构建DOM,但仍会识别该脚本后面的资源,并提前加载。
- 注意:这里是指的浏览器资源加载策略,而非前文提到的resource hint 标准中的preload
使用defer延迟脚本执行
<script src=='index.css' defer><script>
- 当script 标签拥有defer 属性时,该脚本会被退到整个HTML文档解析完成后,再开始执行。
- 被defer 脚本, 在执行时会严格按照HTML文档中出现的顺序位置
延迟脚本方法对比
使用的的方法,可提早脚本资源加载
由于HTML Parser 是增量解析 HTML文档的,因此将脚本放在head中,可以提早浏览器对脚本文件的加载。
使用async 异步加载脚本
- 当script 标签拥有async 属性时,该脚本不会再阻塞html parser 且不会被css 阻塞
- 脚本只要加载完成,便可开始执行
- 被async 的脚本,在执行时会 不会按照在html文档中出现的顺序文档执行
- async 适用于无依赖的独立资源
<link href='https://fints.googleapis.com/css...'>
<style type='text/css' media='screen. print'>
h1 {
font-family:'Roboto'
}
//加载完HTML 文档后, 浏览器会如何工作?
// 等字体文件加载完成后显示内容
</style>
font 阻塞内容渲染
- 浏览器为了避免FOUT(Flash Of Unstyled Text) 会尽量等字体加载完成后, 再显示应用了该字体的内容
- 只有当字体超过一段时间仍未加载成功时, 浏览器才会降级使用系统字体,每个浏览器都规定了自己的超时时间
- 但这也带来了FOIT(falst Of invisible Text) 问题, 内容无法尽快被展示,导致空白。
异步加载字体
通过异步加载css 。即可避免字体阻塞渲染
<body>
<img src='smile.png'>
<p>hello world</p>
</body>
//图片资源是否会阻塞首次渲染 答案是不会
优化关键渲染路径
优化目标
将一下指标压缩到最低
- 关键资源数
- 关键资源体积
- 关键资源网络来回数
勿盲目内联资源
- 若启用HTTP2 ,则无需内联资源
- 若资源被多个页面共享,则无法充分利用缓存, 导致重复下载
结合内联与缓存
<html>
<head>
<style></style>
<link rel='prefetch' href = 'index.css'></link>
</head>
<body>
<p> hello world</p>
</body>
</html>
- 当用户首次访问时,返回内联资源,并通过prefetch,请求并缓存资源;
- 在用户首次访问时, 通过cookie 表示用户已加载缓存
- 当下次访问时, 若cookie 标示已经缓存过,则只返回外部资源标记
- 缓存策略可灵活选择
减少内容大小
- 避免返回无用内容
- 针对特定语言的源码压缩
- 通过文本压缩
- 图片压缩
关键呈现路径优化思路
- 延迟或异步加载资源, 从而减少关键资源数量
- 减少资源大小
- 针对关键资源, 减少网络请求时间
学习资源
- 关键资源呈现路径, by Chrome Developer
- 使用Chrome Devtool 检查性能
- 性能优化相关资源汇总