JavaScript 渲染树
从现在开始,知识要进行一个深入的了解了,
什么是深入了解?
深入了解就是,原来只知道一个表面的东西,这么来的、这么用,
现在除了知道怎么来的、这么用,还要知道每一步是怎么来的,为什么这么用。
先说页面,
页面由HTML、CSS、Javascript这三个组合成的复合格式,
比如写一页面里面有HTML、CSS,最后会把页面展示给我们,但是在展示给我们的时候叫页面已经绘制完成了,
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> div{ width: 100px; height: 100px; background-color: aqua; } </style> </head> <body> <div></div> </body> </html>
什么是绘制页面?
浏览器里面有一个渲染引擎,他会一行一行的绘制页面,
一行就是以一个像素的高度为单位,一行一行的这么绘制,
就像3D打印一样,一层一层把东西打印完,
绘制页面也是一样,会按照HTML、CSS语法去绘制页面。
然后页面上写一个的DIV元素,在写一个CSS样式
CSS是怎么和DIV元素联系到一起的?
怎么的一个加载顺序?
HTML和CSS是怎么执行的呢?
在系统内核的内部,他不认识我们写的DIV和CSS,他不会认识代码的,
内核是不会让他俩产生链接的,他是怎么办的呢?
浏览器里面的内核,会对页面进行一步一步的检索,
首先,先识别我们写的HTML代码
然后会把一大堆HTML代码(比如写了一大堆标签),形成一个叫domTree(dom树)的东西,
<div></div>
<span></span>
<strong>
<em></em>
</strong>
一、domTree(dom树)
第一个概念叫dom树(domTreed),dom树会把整个页面的html代码一行一行去识别,识别后挂到一颗树形结构上,
树的顶端是html标签,树的左侧是head标签,右侧是body标签
浏览器会把html代码每一个节点,放到树形结构对应的位置里面去,
也就是说根据节点的排列方式,来绘制出一个dom树,叫dom节点的树形结构,
而且绘制dom树复核一个原则,叫深度优先原则。
1、什么叫深度优先?
深度优先就一条道走到黑,
看完html完之后,会先看左侧的head,然后再看head里面有什么东西,
head里面有meta绘制meta,有title绘制title,走到头之后,再反过来,
看另一条枝干body,深度优先原则。
2、怎么形成一个dom树呢?
形成dom树,要把这些节点都放在dom树上
<div></div>
<img src="xxx">
<iframe src="xxx"></iframe>
<img src="yyy">
<span></span>
<strong></strong>
现在有一个问题?
遇到div的时候,解析div把他结构放到dom树上,这个没问题,
碰到img的时候,是要等src把文件引入进来下载完,才把img节点挂在dom树上,还是看到img之后就把他挂到dom树上?
就是下载完才把img挂到dom树上,还是读完看到img就挂到dom树上了?
生成dom树的过程,叫dom节点的解析,解析的意思就是,认识这个节点是什么就可以了,
没必要把里面的所有的文字、所有的内容全加载完。
所以读到img的时候,系统一扫这个img标签,
该下载下载,不能下载完,就先把img节点挂在dom树上。
dom树的完成,代表所有dom节点的解析完毕,并不是所有dom节点的加载完毕,
也就是说所有dom节点的加载完,一定在解析完发生之后,
下载完一定在解析完之后,解析完dom树就形成了,什么时候下载完要等一段时间,
比如图片很大要等一会,但是还没等下载完 就 解析完了,
这是一个异步发生的过程,就是同时发生的。
问一个问题
如果dom节点解析到最后了,一定意味着页面展示完毕了吗,或者说一定意味着页面里面的东西都下载完了吗?
不一定,因为解析完一定发生在前面。
接下来说css
二、cssTree(css树)
domTree(dom树)生成之后什么都不干,等着,
等cssTree树形成,
css树就是系统根据我们写的css,也形成跟dom树类似的一个树叫css树,
跟dom节点都是对应的,css树跟dom树都一样深度优先,
css树生成完之后,会和dom树拼到一起,生产一个新的树叫randerTree
domTree + cssTree = randerTree
三、randerTree
randerTree形成完了之后,渲染引擎才会真正的开始绘制页面,
按照randerTree里面每一条的规则去绘制页面,
每一条节点应该怎么绘制,在什么样的位置出现,符合什么样的原则。
js可以动态的改变dom结构,间接的影响css,
由于randerTree是页面最后绘制的依据,如果改变一个dom的结构(删除一个或增加一个dom节点),
dom树就变了,dom树一变randerTree就要重新去构建。
randerTree重新构建,这个页面就要重新绘制,从第一行绘制到最后,这样会浪费效率,
所以dom优化的前提是,尽量减少dom节点的添加、删除这种,
即使做的话,做好要一次性的做完,不要一会做一次,这样反复做,会反复进行reanderTree的构建,
这种reanderTree的重新,我们叫reflow重排或者重构,dom操作里面重构是效率最低的。
四、reflow重排
哪几种情况会触发重构呢?
1). dom节点的增删改查,
具体的说是dom节点的删除、增加,会发生一系列改变
2). dom节点的宽高变化,
上面一个方块宽高变了之后,会影响下面所有方块的位置,
下面所有方块的位置都会重新绘制,这样也会重新构建reanderTree,
凡是重新构建reanderTree的过程都是低效的过程,尤其的大刀阔斧的从根一起改,都会印象页面的效率
3). 位置变化
4). display:none变成了block,这些都算改变位置
5). offsetWidth、offsetLeft这些语法,感觉上是查看dom节点的宽度,dom节点的位置,怎么也会触发重排?
当调用offsetWidth和offsetLeigth,会计算dom节点的宽度和高度,
但是系统会基于这样的一个原则,系统会把reanderTree重新构建一遍,然后重新渲染页面,
这样才能保证求出的结果是时实的,所以他会重构reanderTree,这时候也会触发重排。
具体的细则vip课程去讲,现在了解一个概念叫reflow重排,编程要避免重排,
还有一种效率也是低的,但是相比较而已,效率低的可以有情可原,叫repaint重绘
五、repaint重绘
比如给一个dom节点改变背景颜色,但凡改一个东西,reanderTree都会重新构建的,
只不过是基于什么重新构建,如果是基于css的颜色重新构建的话,不会全把reanderTree改变,
会把css树的一部分改变了,然后在对应的reanderTree上面,把那一部分进行改变,
也就是说影响比较小,重绘的只是这一部分,不会是整个页面都重绘,
所以repaint浪费的效率就很小,是可以接受的,
比如改字体颜色,改背景图片,背景图片的位置随便改,不会影响元素。