浏览器的回流与重绘

基础

1 .浏览器使用流式布局模型
2 .浏览器会把html解析成DOM。把css解析成CSSOM ,dom和cssom合并就产生了render tree
3 .有了render tree就知道了所有的节点的样式,然后就会计算他们在页面上的大小和位置,最后把节点绘制到页面上
4 .由于浏览器使用流式布局,对render tree只需要遍历一次就可以计算出所有的div样式,但是table元素例外,他们需要多次计算,而且要花普通元素的三倍的时间。所以要尽量避免使用table布局

回流

1 .当渲染树种部分或者全部元素的尺寸,结构,或者某些属性发生变化的时候,浏览器重新渲染部分或者全部文档的过程叫做回流
2 .导致回流的操作

1 .页面首次渲染
2 .浏览器窜口大小发生变化
3 .元素尺寸或位置发生改变
4 .元素内容变化,文字数量或者图片大小等
5 .元素字体大小变化
6 .添加或者删除可见的 dom 元素
7 .激活css伪类
8 .查询某些属性或者调用某些方法

3 .导致回流的某些属性或者方法

1 .clientWidth,clientHeight,cliengTop,clientLeft
2 .offsetWidth,offsetHeight,offsetTop,offsetleft
3 .scrollWidth,scrollHeight,scrollTop,scrollLeft
4 .scrollIntoView(),scrollintoViewIfNedded()
5 .getComputedStyle()
6 .getBoundClientRect()
8 .scrollTo()

4 .回流的代价非常大。有时候回流一个单一的元素,他的父元素和跟随他的子元素也会产生回流
5 .现代浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值,浏览器就会将队列清空,进行一次批处理,这样就可以把多次回流和重绘变成一次。当访问上面的方法或者属性的时候,会立刻清除队列。除了上面那些,还有height,width

重绘

1 .当页面中的元素样式的改变并不影响他在文档中的位置时,color,background-color,visibility。元素将会将新样式赋予元素并重新绘制他
2 .

css方法避免

1 .不要使用table布局
2 .在dom树的最末端修改class
3 .避免设置多层内联样式
4 .将动画效果应用到position:absolute,fixed元素上
5 .避免使用css表达式 calc()

js避免

1 .最好一次性重写style样式,或者将样式列表定义为class操作一次性修改
2 .避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来
3 .多所有复杂动画的元素使用绝对定位使他脱离文档流,否则会引起父元素及其后续元素频繁回流

帧维度解释渲染过程

1 .浏览器渲染页面的render进程,涉及到了两个线程。两者通过名为commit的消息保持同步

1 .main线程:浏览器渲染的主要执行步骤,包含从js执行到composite合成的一系列操作
2 .compositor线程:接收用户的一些操作,比如滚动=>唤起main进程进行操作=>接收main线程的操作结果=>commit给真正页面draw到屏幕上的GPU进程
v2-e893a683add1fe8e77e6e6d7676e2662_720w.png

2 .每一个标准帧渲染时间16.7ms之内,浏览器需要完成main线程的操作,并commit给compositor进程
3 .丢帧操作


v2-70a86a3d3b7960a173a8d195b08a5179_720w.png

4 .主线程操作太多,耗时长,commit的时间被推迟,浏览器来不及将页面draw到屏幕,就会丢帧
5 .

浏览器主要执行步骤

1 .js 包含于视觉效果相关的js操作,包括并不限于dom更新,元素样式动态改变,jquery的animate函数

DOM.gif

2 .style:样式计算 。这个过程,浏览器根据css选择器计算哪些元素应该应用哪些规则,然后将样式规则落实到每个样式上去,确定每个元素具体的样式
3 .layout:布局。知道对一个元素应该应用哪些故意则之后。浏览器开始计算他要占据的空间大小以及在屏幕中的位置
4 .painting:绘制。绘制是填充像素的过程,设计绘出文本,颜色,图像,边框和影音。基本上包括元素的每个可视部分,回值一般是在多个表面上完成的,也叫层。paint是把内容填充到页面,而draw是把页面反映到屏幕上
5 .composite:合成。由于页面的各部分可能会绘制到多层,由此他们需要按照正确顺序绘制到屏幕上,以便正确渲染页面,
v2-dc215f24f675d36e32fd052f56191b4a_720w.jpg

6 .浏览器渲染原理 http://taligarsiel.com/Projects/howbrowserswork1.htm
7 .具体流程

1 .Compositor 线程接收一个vsync信号,表示这一帧开始
2 .Compositor线程接收用户的交互输入,然后commit给Main线程,这里有两点规则需要注意
2.1 .并不是所有的event都会commit给main线程,部分操作比如单纯的滚动事件,打字等输入,不需要执行js,也没有需要重绘的场景,Compositor就自己处理了,无需请求main线程
2.2 .同样的事件类型,不论一帧内被compositor线程接收多少次,实际上commit给main线程的,只会是一次,意味着也只会被执行一次


3 .Main线程执行从js到Composite的过程,也有两点需要注意
3.1 .注意红线操作,可能会在js里强制重排,当访问到上面提到的属性和方法的,会触发这个效果导致style,layout前移到js代码执行过程前

4 .当main线程完成最后的合成之后,与compositor线程使用commit进行通信,Compositor调起Compositor Tile work来辅助处理页面
5 .paint结束之后,这一帧就结束了,GPU进程里的GPU线程负责把render进程操作好的页面,交给GPU,调用GPU内方法,把页面draw到屏幕上
6 .屏幕刷新,我们在浏览器是行看到了新页面

预加载扫描器

1 .浏览器构建DOM树时,这个过程占用了主线程。当这种情况发生时,预加载扫描仪将解析可用的内容并请求高优先级资源,如CSS、JavaScript和web字体。多亏了预加载扫描器,我们不必等到解析器找到对外部资源的引用来请求它。它将在后台检索资源,以便在主HTML解析器到达请求的资源时,它们可能已经在运行,或者已经被下载。预加载扫描仪提供的优化减少了阻塞
2 .绘制可以将布局树中的元素分解为多个层。将内容提升到GPU上的层(而不是CPU上的主线程)可以提高绘制和重新绘制性能。有一些特定的属性和元素可以实例化一个层,包括

浏览器渲染

1 .一旦浏览器收到数据的第一块,它就可以开始解析收到的信息。“推测性解析”,“解析”是浏览器将通过网络接收的数据转换为DOM和CSSOM的步骤,通过渲染器把DOM和CSSOM在屏幕上绘制成页面。

DOM是浏览器标记的内部表示。DOM也是被暴露的,可以通过JavaScript中的各种API进行DOM操作。

即使请求页面的HTML大于初始的14KB数据包,浏览器也将开始解析并尝试根据其拥有的数据进行渲染。这就是为什么在前14Kb中包含浏览器开始渲染页面所需的所有内容,或者至少包含页面模板(第一次渲染所需的CSS和HTML)对于web性能优化来说是重要的。但是在渲染到屏幕上面之前,HTML、CSS、JavaScript必须被解析完成
2 .初始第一帧传输的数据为14kb.这就是慢启动

你可能感兴趣的:(浏览器的回流与重绘)