内容简介:Chrome DevTools的performance面板可以记录和分析页面在运行时的所有活动。配合无痕模式,可以避免chrome插件的影响。上面部分是帧数信息:
Chrome DevTools的performance面板可以记录和分析页面在运行时的所有活动。
配合无痕模式,可以避免chrome插件的影响。
帧率图
1. 录制查看
上面部分是帧数信息:
1312.3ms 1fps
下面部分是网页快照,浏览器按照一定时间间隔截取。
2. 实时查看
快捷键 ctrl + shift + p
可以实时查看帧率
还可以进行其它配置
- Paint Flashing 高亮显示网页中需要被重绘的部分。
- Layer Borders 显示Layer边界。
- FPS Meter 每一秒的帧细节,帧速率的分布信息和GPU的内存使用情况。
- Scrolling Performance Issues 分析鼠标滚动时的性能问题,会显示使屏幕滚动变慢的区域。
- Emulate CSS Media 仿真CSS媒体类型,查看不同的设备上CSS样式效果,可能的媒体类型选项有print、screen
火焰图
- Loading:网络通信和HTML解析
- Scripting:Javascript执行
- Rendering:样式计算和布局,即重排
- Painting:重绘 对应的详细事件
怎么看出性能问题?
1. 红色小三角
常见的原因为:
- handler took xxx ms 操作消耗太多时间
- forced reflow is likely performance bottleneck “强制同步布局”可能会导致性能问题,通常是因为修改样式后读取属性,导致了浏览器必须重新渲染以获取最新的属性值。
2. 布局抖动
“布局抖动”是指反复出现“强制同步布局”情况。 这种情况会在 JavaScript 从 DOM反复地写入和读取时出现,将会强制浏览器反复重新计算布局。布局抖动也会导致长帧,使页面卡顿。
3. 长帧
长帧表示一帧的时间过长,会影响页面的加载速度与动画的流畅性,这时会感受到页面加载慢或动画卡顿。
动画播放时每秒的帧数最好能够达到60帧,也就是每帧16.6ms。
实例
1. 解析html(不包含js css外部文件)
- readystatechange(第一个)(文档已加载和解析) 此时状态为interactive,表示文档已加载和解析但资源仍在加载,该状态通常紧接着会触发DomContentLoaded。
- DOMContentLoaded (DOM树构建完成) html文档被加载和解析成功,DOM树构建完成时会触发。
- Recalculate Style(CSSOM构建完成) 通过添加和删除元素,更改属性、类或通过动画来更改 DOM,全都会导致浏览器重新计算元素样式,在很多情况下还会对页面或页面的一部分进行布局(即自动重排)。重新计算样式的步骤可以分为两步:
- 浏览器计算出给指定元素应用哪些类、伪选择器和 ID。
- 从匹配选择器中获取所有样式规则,并计算出此元素的最终样式。
- readystatechange(第二个)(文档已加载和解析,且资源也加载完成) 此时状态为complete,表示文档和资源都已加载完成,该状态通常紧接着会触发load。
- load事件 文档和资源都已加载完成时会触发。
- Layout 布局几乎总是作用在整个文档,但还是主要看影响的节点个数。
2. 解析html(包含js css外部文件)
- Evaluate Script (执行js)
- layout变为不在ParseHtml中执行 可能是因为CSS文件或JS文件的加载阻塞了整个页面的渲染过程,因为js和css都可能对标签进行样式的设置。如果不存在文件,就不会存在等待加载的问题。
3. 改变背景色(重绘)
4. 改变高度(重排)
相对于重绘多了个Layout
5. 图片资源加载(img或bg)
如果图片标签尺寸不变,则会触发一次重绘
6. 浏览器插入一段script
- 未插入
- 插入
可以发现只要插入script,不管有没有改变dom,chrome浏览器在之后马上会进行一次重排。
遵循的原则
1. 关于阻塞
- css 不会阻塞 DOM树的解析
- css加载 会阻塞 js ,从而阻塞了DOM树的解析,页面渲染(所以内联样式性能较高,适用于第一屏)
- js 会阻塞 DOM树的解析 (因为js会改变DOM树内容)
- css引入的字体文件加载 也会阻塞 js , 页面渲染
2. 关于与页面渲染过程的对应
- js执行时 :这时应该只是构建了前面部分的dom树和CSSOM树,因为js需要通过dom api和CSSOM api操作前面部分的标签的内容和样式。
- DOM树构建完成 :DomContentLoaded事件
- CSSOM构建完成、Render Tree构建完成 :Recalculate Style
- Layout :Layout事件
- paint :Paint(图片层绘制) 和 Composite Layers(图片层合并), 除了transform 或 opacity属性之外,更改任何属性始终都会触发绘制Paint 。
- reflow重排 :3 4 5步走一遍
- repaint重绘 :3 5步走一遍
- 更改一个既不要布局也不要绘制的属性:3步 + Composite Layers,此行为在678重新渲染步骤中开销最小,适合动画或滚动,具体比如transfrom opacity。
3. 关于chrom浏览器的一些行为
- 渲染队列:浏览器存在一个队列,用于将多次的回流和重绘变成一次。当你读取DOM的属性和方法时,chrome不会清空队列(网上说会清空队列,立即进行回流和重绘),如果读取时发现样式有改变,chrome只是会Recalculate Style重新计算样式,如果没有改变,chrome甚至不会做出多余的操作。
- html中的script标签执行完后一定会reflow
性能优化
阻塞优化
- js存在问题: 1)js加载和执行都会阻塞DOM解析和页面渲染 2)如果引用第三方脚本,当第三方服务商请求延迟时,页面会白屏; js解决办法: 页面可以通过添加关键字defer和async来异步加载js。
- 两者都是异步加载,不同的是: async(参考ajax):异步加载时不会阻塞DOM解析和页面渲染;执行时间为加载完成时;执行时会阻塞,但这时可能DOM已经解析完成,甚至页面已经渲染;另外会影响js文件执行顺序。 defer:异步加载时不会阻塞DOM解析和页面渲染;执行时间为DOM解析完成之后、DOMContentLoaded事件之前(所以会阻塞DCLoad事件和jquery的ready事件);执行时DOM已经解析完成,只会阻塞页面渲染。
- js文件加载顺序 同步 > 异步 同是async 按加载完成顺序 同是defer 按引入顺序 async defer 正常不一起用
减少重新渲染
关于CSS
- 使用简单的样式表。样式表越简单,重排和重绘就越快。具体为:
- 减低选择器的复杂性,少用伪类;使用以类为中心的方法,例如BEM;
- 减少必须计算其样式的元素的数量,应当尽可能减少声明为无效的元素的数量。
- 减少DOM元素层级。重排和重绘的DOM元素层级越高,成本就越高。
- 多利用display:none。display:none的元素没有在渲染树,因而也不会进行重排和重绘
- 使用CSS动画而不是JS动画。CSS动画优于JS动画,是由于CSS改变的是translate的值,不会引起offsetLeft、offsetTop等位置值的改变。
- 使用absolute而不是float。position属性为absolute或fixed的元素在重排的开销比float少,因为不用考虑它对其他元素的影响。
- 使用div而不是table。因为一个很小的改动可能都会引起整个table的重新布局,比如说td内容改变。
关于JS
- DOM的多个读操作(或多个写操作)应该放在一起,不要穿插进行。因为 连续地设置元素样式(写操作),浏览器会一次性执行,即只触发一次重排或重绘 ,但如果在几个写操作间插入读取样式的操作,浏览器则不得不立即重排或重绘。(好像不生效)
- 一次性改变样式。不要一条条地改变样式,而要通过改变class,或者el.style.csstext属性。
- 使用离线DOM来改变元素样式。比如
cloneNode()
克隆节点,然后再替换掉元素节点 或者display:none → 改动 → 显示
。 - 尽量修改层级较低的DOM。
- 不要在循环中重复读取DOM节点属性值。
- 使用 window.requestAnimationFrame()、window.requestIdleCallback() 这两个方法控制重新渲染。
提高fps(frame per second)
网页动画的每一帧(frame)都是一次重新渲染,将一帧送到屏幕会采用如下顺序:
帧数与动画流畅度的关系如下:
fps > 刷新频率
这里想说地是 fps最好能达到浏览器刷新频率 ,因而在播放动画的时候,注意不要执行太多耗时耗性能的操作。
手动控制重新渲染
window.requestAnimationFrame() 方法可以将某些代码统一放到下一次重新渲染时执行。具体是将js代码放在下一帧开始时执行。如果使用setTimeout 或 setInterval 来执行动画之类的视觉变化,其回调可能在帧的某个时间点执行,可能在末尾,这会使我们丢失帧,导致卡顿。
- 处理“布局抖动” 反复读写属性会导致布局抖动,导致长帧。
function doubleHeight(element) { var currentHeight = element.clientWidth; element.style.width = (currentHeight / 2) + 'px'; element.style.height = '80px'; } var elements = document.getElementsByTagName('tr'); for (var i = 0; i < elements.length; i++) { doubleHeight(elements[i]); } 复制代码
将doubleHeight函数改成下面这样:
function doubleHeight(element) { var currentHeight = element.clientHeight; window.requestAnimationFrame(function () { element.style.height = (currentHeight * 2) + 'px'; }); } 复制代码
2)页面滚动事件(scroll)
$(window).on('scroll', function() { window.requestAnimationFrame(scrollHandler); }); 复制代码
3)最适合用于动画
结合项目
1)现在项目中,页面(以“任务”页面为例)在加载时都会请求一些ajax数据,比如datagrid,tree数据等等,还有些ajax数据只是预加载。如果这些ajax在页面渲染前完成请求,则会阻塞页面渲染。所以同一个页面不同网速下会有两种渲染顺序:
- 在渲染之后执行
- 在渲染之前执行
解决办法
- 在所有资源加载完后进行ajax请求。将datagrid等控件的数据加载放在$(window).load()事件中。
- 延迟初始化modal中的内容
效果
问题
问:只要执行js,都会重排吗?
答:执行js的发生情况如下:
- 载入页面时script标签:不管有无改变dom,都会重排
- 异步ajax回调:需要判断有无改变dom
- setTimeout:需要判断有无改变dom
问:请求js文件时,请求和执行顺序是什么?
答:请求会一起发出;执行顺序按引入的顺序,不会因为后一个先返回数据而先执行。
问:页面加载时提前ajax请求一些数据,会不会影响性能?
答:可能会,可能不会。ajax请求时不影响性能,请求后执行回调函数会影响。ajax回调函数会在请求完成且js主程序运行完后执行,等到我们能看到页面,需要经历页面解析和渲染这两个过程,如果页面渲染前ajax回调执行了,那将阻塞渲染过程。
问:为什么jquery通常在onReady中执行代码?
答:onReady 监测的是 DOMContentLoaded事件,也就是监测DOM树构建完成。
附录
loading 事件
事件 | 描述 |
---|---|
Parse HTML | 浏览器执行HTML文件解析 |
Parse Stylesheet | 浏览器执行CSS文件解析(单指外部CSS文件) |
Finish Loading | 网络请求完毕事件 |
Receive Data | 请求的响应数据到达事件,如果响应数据很大(拆包),可能会多次触发该事件 |
Receive Response | 响应头报文到达时触发 |
Send Request | 发送网络请求时触发 |
Scripting事件
事件 | 描述 |
---|---|
Animation Frame Fired | 一个定义好的动画帧发生并开始回调处理时触发 |
Cancel Animation Frame | 取消一个动画帧时触发 |
GC Event | 垃圾回收时触发 |
DOMContentLoaded | 当页面中的DOM内容加载并解析完毕时触发 |
Evaluate Script | A script was evaluated. |
Event | js事件 |
Function Call | 只有当浏览器进入到js引擎中时触发 |
Install Timer | 创建计时器(调用setTimeout()和setInterval())时触发 |
Request Animation Frame | A requestAnimationFrame() call scheduled a new frame |
Remove Timer | 当清除一个计时器时触发 |
Time | 调用console.time()触发 |
Time End | 调用console.timeEnd()触发 |
Timer Fired | 定时器激活回调后触发 |
XHR Ready State Change | 当一个异步请求为就绪状态后触发 |
XHR Load | 当一个异步请求完成加载后触发 |
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 通过分析 WPF 的渲染脏区优化渲染性能
- 用 dotTrace 进行性能分析时,各种不同性能分析选项的含义和用途
- Golang 性能测试 (2) 性能分析
- 性能分析方法论
- 十大MySQL性能分析工具汇总!专治MySQL性能瓶颈
- JProfiler性能分析工具详解
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。