当前位置: 首页 > Web前端 > CSS

借助performance工具直观理解浏览器的渲染过程

时间:2023-03-31 12:06:54 CSS

使用性能工具直观了解浏览器的渲染过程?直观展示为了更好的理解这个过程,我们在Chrome内置的开发工具中使用了一个工具来帮助表现(旧版本和其他浏览器都是timeline),点击录制,然后在地址栏这里输入我们的url以百度为例,输入www.baidu.com,回车点击录音结束,可以看到这个网络请求。我们首先看到的是这个字面意思,可以理解。浏览器正在向服务器发送请求并接收响应。Header和responsebody但实际上,在此之前,浏览器已经做了一些事情来知道将请求发送到哪个服务器。根据url,先到本地DNS缓存列表中查找对应服务器的IP地址和端口号,如果没有找到,继续查找系统缓存和路由缓存,如果找到则跳转到第三步,如果没有找到,则请求本地DNS服务器,如果没有,则将该域名发送给其他服务器,递归查找,从根域名服务器开始,继续向下递归,直到返回对应的IP地址和端口号并缓存,根据IP地址和端口号,与目标服务器建立TCP连接(三次握手)这三个步骤我们是看不到的,接下来我们观察到的就是浏览器向目标服务器发送http请求服务器,并接收返回的响应头和响应体。继续往下看。黄色部分是浏览器的一些默认行为,包括隐藏原来标签页的内容等,下面的RecalculateStyle(重新计算样式),Layout(重新排列)是清除原来的页面,为新页面做准备。不用管,中间我们又看到了ReceiveData,因为发送数据的时候服务器可能会反汇编。浏览器比较勤快,多次发送和解析html包。它不是等html全部接收完才开始解析,而是接收到一部分后才开始解析HTML的一部分。Parser的任务是将HTML标签解析成DOMTree,这是一个深度遍历的过程,只有遍历完Dom下的子节点,才遍历下一个同级的Dom节点。同时,在解析过程中,如果遇到图片、链接标签、脚本标签,就会向服务器发送请求。比如上图中,我们遇到百度的logo图片,请求下载js解析。遇到js,我们马上分析下载执行,不管是inline还是external,都会阻塞后续的dom分析和渲染,所以一般把标签中加上defer或者async属性defer,这样js的下载就不会影响后面对html的解析,在html解析完成后执行js文件完成了,会跟原来的下载顺序异步也可以让js的下载不影响后面的html解析,但是一旦下载完成就会马上执行,所以不保证css解析一定会执行按照下载顺序。当遇到内联css样式时,会解析外部css文件,接收到后再解析外部css文件,两者都不会阻塞Dom的解析,但是会阻塞Dom的渲染。这就是为什么css的标签要放在中。当css文件放在中时,虽然css的解析也会阻塞后续dom的渲染,但是在解析css的同时也在解析dom,所以页面会在css解析完成后逐渐渲染。将css语句解析成CSSOM渲染布局后绘制DomTree和CSSOM,浏览器会构建RenderTree(渲染树)。其实DOMTree和CSSOM是依附的,所以RenderTree其实是一个计算出来的样式,不包含display:none等不占空间的元素。然后浏览器根据这个RenderTree进行第一次布局(Layout)和绘图(Paint)重排和重绘。第一次绘制完成后,浏览器会继续从服务器接收数据图片和css文件,js文件可能有导致页面布局改变或者样式改变的内容,会被添加到我们的RenderTree中导致回流(Layout)或者重绘(Paint)。否则,回流(Reflow)导致操作页面第一次回流。浏览器窗口的大小发生变化。元素的大小或位置发生变化。CSS伪类(例如::hover)设置style属性,是不是一遇到就重新排列?并不是说浏览器会有渲染队列来优化。积累一定数量或一定时间后,内容将重新排列。However,whenaspecificattributeisaccessed,forexample,aconsole.log(body.clientWidth)会强制刷新渲染队列以下属性的访问会立即刷新渲染队列widthheightmarginpaddingdisplayborderpositionoverflowclientWidthclientHeightclientTopclientLeftoffsetWidthoffsetHeightoffsetTopoffsetLeftscrollWidthscrollHeightscrollTopscrollLeftscrollIntoView()scrollTo()getComputedStyle()getBoundingClientRect()scrollIntoViewIfNeeded()所以访问这些属性要慎重,最好分开阅读,以免受过许多的影响性能重绘通常是通过修改元素的属性引起重绘。重新排列和重新排列绘制,尤其是重排,尽量不要在布局信息变化时做查询(会导致渲染队列被强行刷新),减少DOM操作。同一个DOM的多个属性变化可以写在一起。在本地方法中,多次访问同一个Dom,先暂存其引用,批量添加DOM。可以先让元素脱离文档流,操作后再带入文档流。这只会触发一次重排(应用fragment元素)并且需要多次重排对于元素,position属性设置为absolute或fixed。比如有动画效果的元素,用更好的API替代高消耗的API,对高消耗的集合进行转换和优化,比如用querySelectorAll()代替getElementByXX()。为动画开启GPU加速并使用较少的HTML集合(array-like)来遍历,因为集合遍历比真正的数组遍历更昂贵。使用事件委托来减少事件处理程序的数量。避免设置大量的style属性,因为每次设置都会触发reflow,所以最好使用class属性动画来达到速度过于精细流畅,会造成reflow过于频繁。不要使用表格布局,因为一旦触发了表格中的某个元素,如果设置了重排,则整个表格都会重排。您可以设置表格布局:自动;或table-layout:fixed只允许回流一行,减少通过JavaScript代码修改元素样式,尽量使用修改类名的方式来操作样式或动画;隐藏在屏幕外,或者页面滚动时,尽量停止动画;最后,大家可以自己尝试performance的使用,可以更直观的了解浏览器的工作流程。参考文章https://segmentfault.com/a/11...https://segmentfault.com/a/11...https://sylvanassun.github.io...https://www.imooc.com/article...https://segmentfault.com/a/11...