1.首先网络线程会去下载 html 当拿到html 的时候放到 事件队列等待执行
2.拿取任务然后解析
1.解析HTML -Parse HTML
1.首先网络线程会去下载 html 当拿到 字节文件 的时候放到 事件队列等待执行
2.拿取任务然后解析
1.解析HTML -Parse HTML
1.首先生成dom树这个树是c++树,但是被转换成js对象树了所以可以用js拿到这个树,当在解析html的时会开启一个预解析线程去下载css,在解析html的过程中如解析的link元素但是没有下载好这个时候的主线程不会等待下载完成而是会继续往下解析,得此结论,所以外部css并不会直接的影响html的解析,等到css下载完成预解析线程会先去解析css,解析css的时候会生成cssom树,这个树同样是c++的对象树,跟html树同理,解析完成的cssom树交给渲染主线程执行
预解析还会去率先下载js帮助渲染主线程分担压力,但是不会去执行,是交给渲染主线程执行,当解析到js部分的时候会卡住等待js下载完成把js执行完了之后才会去往下执行
这一步完成会得到DOM树CSSOM树,浏览器的默认样式、内部样式、外部样式、行内样式都会在CSSOM中这个就是第一步了主要是为了下载解析DOM浏览器为了提升效率然后会开一个预解析的线程去率先下载css并解析好了给主线程
css的下载单独不影响第一步,html的解析,但是会阻塞渲染,css过慢还是会等待下载结束之后才会渲染的
这里的树是指抽象语法树,AST
这一步完成会得到DOM树CSSOM树,浏览器的默认样式、内部样式、外部样式、行内样式都会在CSSOM中这个就是第一步了主要是为了下载解析DOM浏览器为了提升效率然后会开一个预解析的线程去率先下载css并解析好了给主线程
2. 样式计算 - Recalculate Style
主线程会遍历所有的DOM,依次为树中的所有节点计算出最终的样式,属性的计算过程就发生在这一步
1.确定声明值:参考样式表中没有冲突声明的作为css属性值就是看作者样式表和浏览器默认样式表有没有冲突,如果没有冲突的话就用上
2.层叠冲突:对样式有冲突的使用层叠规则,确定CSS属性值比较重要性,作者样式表大于浏览器默认样式表,然后又比较特殊性,比较源次序后写的大于先写的这个解决层叠冲突
层叠规则
一.比较重要性
1.带有important 的作者样式表
2.带有important 的浏览器默认的样式这个是要高于的作者样式表的
3.作者样式
4.默认样式
二.比较特殊性
style | id | 属性 | 元素 |
---|---|---|---|
内联 : 1 否则0 | id选择器的数量 | 属性类伪类的数量 | 元素伪类的数量 |
三.对于任然没有值的属性继承可以继承的值
四.使用浏览器的默认值
这步之后预设值会变成绝对值,会得到一颗带有样式的 DOM 树
这步完成之后会把之前解析的dom树和cssom树结合起来
3. 布局 - Layout
布局阶段会依次遍历所有的DOM节点,计算每个节点的几何信息。例如宽高,相对包含块的位置。(包含块是指当前DOM在计算位置百分比宽高的时候的一个参照系)
大部分时候,DOM树和布局树并非一一对应。
比如给DOM设置了display:none这个时候的DOM节点没有几何信息,因此不会生成布局树;又比如使用了伪元素选择器,虽然DOM树中不存在伪元素节点,但它们拥有几何信息,所以会到布局树中,还有匿名块盒,匿名行盒都会导致DOM树和布局树无法一一对应。
我懂这些话对于你来说理解可能太困难了,说直白点吧
上一个流程下来的东西不就得到了一个带有样式的DOM树了吗,但是有些DOM的属性是display:none,他什么都没有了所以不会产生几何信息所以不会加到布局树中,但是像那种透明度设置为1只是你眼睛瞎了看不见,但是还是会有几何信息所以还是会加到布局树中,你就按照这种例子来
匿名盒:w3c规定
1.内容必须在行盒中
<块盒标签>内容</块盒标签> ==> 布局树中 <块盒标签><匿名行盒>内容</匿名行盒></块盒标签>
2.行盒和块盒不能相邻
当出现这种情况的时候会在外面包一个匿名块盒
这个是最终布局树的为什么里面还有一个匿名行盒呢,因为文本是行盒外面套了一个匿名块盒所以里面还要套一个匿名行盒
4. 分层 - Layer
布局完成了就是分层了
这样的好处是将来某一块改变之后只会重新计算那一层的,处理那一层的,这样效率会大大的提升,
那什么东西会影响分层呢?
滚动条,层叠上下文 ,transform,opacity这些多多少少的都会有点影响分层的结果,滚动条是因为他和页面操作无关,而且滚动条也是在最后一步的时候才会去绘制出来,滚动条也是浏览器渲染的时候生成的!堆叠上下文呢可以看看下面的链接是什么意思,当一个dom会经常的transform变换的时候可能造成页面性能问题浏览器会自行决定是否要分出一层来单独渲染,opacity呢这个要是给很大块区域设置了里面东西较多浏览器也会考虑分层除去,用户看不见频繁的渲染也没用,那就没必要再重新渲染了,opacity只是透明,但是还有几何信息的还是要占据空间
那有没有说什么设置了什么属性就一定会给这块dom区域分配一层呢?
答案是 :"没有。过多的分层浏览器也是会吃不消的,这个非常耗内存"
will-change这个属性就可以大幅度影响分层的结果,一般都是某一块更新太快了,某块区域变动太大再考虑用这个属性
下面是MDN部分原话
属性 will-change 为 web 开发者提供了一种告知浏览器该元素会有哪些变化的方法,这样浏览器可以在元素属性真正发生变化之前提前做好对应的优化准备工作。这种优化可以将一部分复杂的计算工作提前准备好,使页面的反应更为快速灵敏。
用好这个属性并不是很容易:
- 不要将 will-change 应用到太多元素上:浏览器已经尽力尝试去优化一切可以优化的东西了。有一些更强力的优化,如果与 will-change 结合在一起的话,有可能会消耗很多机器资源,如果过度使用的话,可能导致页面响应缓慢或者消耗非常多的资源。
- 有节制地使用: 通常,当元素恢复到初始状态时,浏览器会丢弃掉之前做的优化工作。但是如果直接在样式表中显式声明了 will-change 属性,则表示目标元素可能会经常变化,浏览器会将优化工作保存得比之前更久。所以最佳实践是当元素变化之前和之后通过脚本来切换 will-change 的值。
- 不要过早应用 will-change 优化: 如果你的页面在性能方面没什么问题,则不要添加 will-change 属性来榨取一丁点的速度。 will-change 的设计初衷是作为最后的优化手段,用来尝试解决现有的性能问题。它不应该被用来预防性能问题。过度使用 will-change 会导致大量的内存占用,并会导致更复杂的渲染过程,因为浏览器会试图准备可能存在的变化过程。这会导致更严重的性能问题。
- 给它足够的工作时间: 这个属性是用来让页面开发者告知浏览器哪些属性可能会变化的。然后浏览器可以选择在变化发生前提前去做一些优化工作。所以给浏览器一点时间去真正做这些优化工作是非常重要的。使用时需要尝试去找到一些方法提前一定时间获知元素可能发生的变化,然后为它加上 will-change 属性。
5. 绘制 - Paint
分层完了接下来就是绘制了
这个绘制不是画页面这个绘制是指绘制指令集,比如某一层如何如何绘制 ,会生成这层的指令集
后面的步骤就交给其他线程了
6. 分块 - Tiling
主线程 绘制完了之后,把绘制的东西提交给合成线程剩下的都由他们完成,当然合成线程也在渲染进程里面,他会去启动更多的线程来分块
第六步干的是分块,把每层分成一个一个的小块,分成一个一个的小的区域
页面有可能很大,有些地方可以先画出来,一般会先画用户视口的小块。分块就是为了让页面有优先级。
7. 光栅化 - Raster
这一步是把上一步块的像素点算出来,这块像素点有多少啊,位置这些都有了,分层也分了,每一块的像素点的颜色是啥啊,之前的工作都做好了都可以算了位置
他会把算像素点的信息交给GPU去计算,GPU相对比CPU会快很多但是能做的事情会相对少很多,这类计算的事情交给他再好不过了
光栅化完成之后会得到一块一块的位图
8. 画 - Draw
最后一步就是画了
但是在画之前要确保一个东西quad这个叫指引信息相对于屏幕的位置在哪里啊应该画哪个位置啊这些信息计算出来,然后把quad交给浏览器的GPU进程然后之后再交给硬件
渲染进程是放在沙盒里面的,这个沙盒是和外界隔离的,这样的好处呢就是安全,假如你下载了恶意插件,病毒,这样最多只会导致浏览器沙盒环境崩塌,不会影响到外界,这个就是沙盒的好处,就是因为与外界隔离了,使用GPU绘制是调用系统接口的函数,所以有一个GPU线程中转一下交给系统硬件,GPU线程不在沙盒里面所以可以调用系统接口
transform这个是在画的时候算出来的旋转,平移,缩放,得到了这位图的时候,然后通过矩阵变换来运算出最终的位置
当别人问你为啥CSS的变换这么快,因为没有任何有关的操作会在主线程上面,也就是你们听到的transform不会影响其他的DOM元素。
即使在js中书写一个死循环,那么使用transorm做的动画也不会有阻塞,这也是teansorm做动画的好处
什么是 reflow?
reflow 的本质就是重新计算 layout 树。
当进行了会影响布局树的操作后,需要重新计算布局树,会引发 layout。
为了避免连续的多次操作导致布局树反复计算,浏览器会合并这些操作,当 JS 代码全部完成后再进行统一计算。所以,改动属性造成的 reflow 是异步完成的。
也同样因为如此,当 JS 获取布局属性时,就可能造成无法获取到最新的布局信息。
浏览器在反复权衡下,最终决定获取属性立即 reflow。
什么是 repaint?
repaint 的本质就是重新根据分层信息计算了绘制指令。
当改动了可见样式后,就需要重新计算,会引发 repaint。
由于元素的布局信息也属于可见样式,所以 reflow 一定会引起 repaint。 此文章出于总结,搬运了别的文章