浏览器渲染原理,以及重绘和回流(重排),基于他们的性能优化

回流也叫重排,叫回流是为了和重绘从字眼上更好区分。

一、网页渲染流程

 浏览器的结构:

  • 用户界面:包括地址栏,前进、后退按钮,书签菜单等。
  • 浏览器引擎:在用户界面和呈现引擎之间传送指令。
  • 呈现引擎:负责显示请求的内容。
  • 网络:用于网络调用,比如HTTP请求;其接口与平台无关,并为所有平台提供底层实现。

    一文读懂计算机底层网络原理,包括TCP、UDP、header,什么是包、帧、段等关键问题

  • 用户界面后端:用于绘制基本的窗口小部件,比如组合框和窗口。其公开了与平台无关的通用接口,而在底层使用操作系统的用户界面方法。
  • JavaScript解释器:用于解析和执行JavaScript代码。

    js上下文:

    1. 解析js代码
    2. 建立对象,变量,函数,参数
    3. 建立作用域链
    4. 确定this指针

  • 数据存储:这是持久层。浏览器需要在硬盘上保存各种数据,例如Cookie。新的HTML规范定义了“网络数据库”,这是一个完整的浏览器内数据库。

 

注意:Chrome浏览器的每个标签页都分别对应一个呈现引擎实例,每个标签页都是一个独立的进程。

 网页的生成过程,大致可以分成五步。

  1. HTML代码转化成DOM Tree
  2. CSS代码转化成CSSOM Tree(CSS Object Model)
  3. 结合DOM和CSSOM,生成一棵渲染树Render Tree
  4. 生成布局(flow),将所有渲染树进行平面合成(!此步骤再次触发即回流)
  5. 将布局绘制(paint)在屏幕上(显卡,此步骤再次触发即重绘)

 

这五步里面,第一步到第三步都非常快,耗时的是第四步和第五步。"生成布局"(flow)和"绘制"(paint)这两步,合称为"渲染"(render)。

即,html(dom tree)+css(cssom tree样式计算)=render tree,重排(回流),重绘。

 

当浏览器获取HTML文件后,会自上而下加载并在加载过程中进行解析和渲染;加载就是获取资源的过程;如果在加载过程中遇到外部的css文件和图片,浏览器会另外发送一个请求,去获取css文件和图片,这个请求是异步的,并不会影响HTML文件的加载;但如果遇到JavaScript文件,HTML文件会挂起渲染的进程,等待JavaScript文件加载完毕后,再继续进行渲染。

为什么需要等待JavaScript呢?

因为JavaScript可能会修改dom,导致后面的HTML资源白白加载,需要等待JavaScript文件加载完成后,再继续渲染,so,JavaScript文件一般写在底部body标签前的原因

整个渲染流程,从HTML到DOM、样式计算、布局、图层、绘制、光栅化、合成和显示。

 

二、重排(dom节点)和重绘

网页生成的时候,至少会渲染一次。用户访问的过程中,还会不断重新渲染。

以下三种情况,会导致网页重新渲染。

  • 修改DOM
  • 修改样式表
  • 用户事件(比如鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等)

重新渲染,就需要重新生成布局和重新绘制。前者叫做"重排"(reflow),后者叫做"重绘"(repaint)。

需要注意的是,"重绘"不一定需要"重排",比如改变某个网页元素的颜色,就只会触发"重绘",不会触发"重排",因为布局没有改变。

但是,"重排"必然导致"重绘",比如改变一个网页元素的位置,就会同时触发"重排"和"重绘",因为布局改变了。

重排跟DOM节点有关,优先级更高

1、延伸,为什么需要DOM树?

为了将HTML转成浏览器能读懂的结构。类似语言解析。

 

 

2、样式计算

当渲染引擎接收到CSS文本时,会执行一个转换操作,将CSS文本转换为浏览器可以理解的结构——styleSheets。属性值标准化的过程:将所有值转换为渲染引擎容易理解的、标准化的计算值。

 

 3、布局

布局:计算出DOM树中可见元素的几何位置,第一创建布局树(构建一棵只包含可见元素布局树),第二布局计算。

面试问题:CSS加载会阻塞页面显示吗?

  • css加载不会阻塞DOM树的解析
  • css加载会阻塞DOM树的渲染
  • css加载会阻塞后面js语句的执行

so,为了避免让用户看到长时间的白屏时间,应该提高css的加载速度。

为了防止css阻塞,引起页面白屏,可以提高页面加载速度

  • 使用cdn
  • 对css进行压缩
  • 合理利用缓存
  • 减少http请求,将多个css文件合并

 

迭代,浏览器的回流和重绘机制

回流/重排(reflow):

当浏览器发现某个部分发生了点变化影响了 布局,需要倒回去重新渲染,内行称这个回退的过程叫 Fef1ow。

reflow 会从这个root frame 开始递归往下,依次计算所有的结点几何尺寸和位置,reflow 几乎是无法避免的。

现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显示与隐藏)等,都将引起浏览器的

reflow。鼠标滑过、点击.…只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,

都会引起它内部、周围甚至整个页面的重新渲染。通常我们都无法预估浏览器到底会reflow 哪一部分的代码,

它们都彼此相互影响着。

 

重绘(repaint):

改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸没有变。

- display:none 的节点不会被加入Render Tree, 而visibility:hidden 则会,所以,如果某个节点最开始是不显示的,设为display:none是更优的。

- display:none 会触发reflow,而 visibility :hidden 只会触发 repaint,因为没有发现位置变化

- 有些情况下,比如修改了元素的样式,浏览器并不会立刻retlow 或 repaint一次,而是会把这样的操作积攒批,然后做一次reflow,这又叫异步 refow 或增量异步relow。

但是在有些情況下,比如resize窗口,改变了页面默认的字体等.对于这些操作,浏览器会马上进行 reflow。

 

三、基于以上考虑网站性能

重排和重绘会不断触发,这是不可避免的。但是,它们非常耗费资源,是导致网页性能低下的根本原因。

提高网页性能,就是要降低"重排"和"重绘"的频率和成本,尽量少触发重新渲染。

前面提到,DOM变动和样式变动,都会触发重新渲染。但是,浏览器已经很智能了,会尽量把所有的变动集中在一起,排成一个队列,然后一次性执行,尽量避免多次重新渲染。

基于这个思想,可以从以下几个方面改进提高网站性能:

  • 样式表越简单,重排和重绘就越快。尽量用class,少用style一条条改变样式
  • 重排和重绘的DOM元素层级越高,成本就越高。如果可以灵活用display,absolute,flex等重排开销会比较小,或不会影响其他元素的重排。(定位和分层z-index,详情看文末延伸文章)
  • 使用虚拟DOM的脚本库,比如React等。diff算法可以只render修改的部分。

 

如何减少和避免重排

Reflow 的成本比 Repaint 的成本高得多的多.一个节点的 Rerlow 很有可能导致子节点,甚至父节点以及兄弟节点的Reflow.在一些高性能的电脑上也许还没什么,但是如果 Reflow 发生在手机上,那么这个过程是延慢加载和耗电的——浏览器的渲染原理简介

- 直接改变className, 如果动态改变样式,则使用css Text(考虑没有优化的浏览器)

- 让要操作的元素进行“离线处理”,处理完以后一起更新

   - 使用DocumentFragment进行缓存操作,引1发一次回流和重绘;

   - 使用display:none技术,只引1发两次回流和重绘

   - 使用cloneNode (true or false)和replaceChild 技术,引1发一次回流和重绘;

- 不要经常访问会引/起浏览器flush队列的属性,如果你确实要访问,利用缓存;

- 让元素脱离动画流,减少回流的Render Tree的规模;

 

 

四、刷新率

很多时候,密集的重新渲染是无法避免的,比如scroll事件的回调函数和网页动画。

网页动画的每一帧(frame)都是一次重新渲染。每秒低于24帧的动画,人眼就能感受到停顿。一般的网页动画,需要达到每秒30帧到60帧的频率,才能比较流畅。如果能达到每秒70帧甚至80帧,就会极其流畅。

一秒之间能够完成多少次重新渲染,这个指标就被称为"刷新率",英文为FPS(frame per second)。60次重新渲染,就是60FPS。

如果想达到60帧的刷新率,就意味着JavaScript线程每个任务的耗时,必须少于16毫秒。一个解决办法是使用Web Worker,主线程只用于UI渲染,然后跟UI渲染不相干的任务,都放在Worker线程。

 

五、开发者工具的performance面板

以前是Timeline面板,Chrome 57已经改为performance(性能模板),这个面板是整个面板里面最复杂的一个面板,涉及的东西比较多。可以利用这个面板来记录和分析网页运行过程中的所有活动行为信息。你可以充分利用这个面板来分析你的网页的程序性能问题。

下图是我对系统总览页面的监控。

 

 左上角的圆点是⏺️,这是录制按钮,按下它会变成红色。然后,在网页上进行一些操作,再按一次按钮完成录制。

不同的颜色表示不同的事件。

  • 蓝色:网络通信和HTML解析
  • 黄色:JavaScript执行
  • 紫色:样式计算和布局,即重排
  • 绿色:重绘

哪种色块比较多,就说明性能耗费在那里。色块越长,问题越大。

以上监控的页面,js执行时间比较长,分析可能是echarts数据分析时间比较长,这个是历史遗留问题了,后端返回的数据不够简洁,得前端处理以后再渲染,当然需要很久啦,当然前端还可以再努力努力,更细致的去降低渲染时间,提高页面性能。

以上。

延伸阅读:浏览器的工作原理:新式网络浏览器幕后揭秘

posted @ 2021-04-19 14:35  优前程  阅读(692)  评论(0编辑  收藏  举报