Go to comments

JavaScript 渲染树

从现在开始,知识要进行一个深入的了解了,


什么是深入了解?

深入了解就是,原来只知道一个表面的东西,这么来的、这么用,

现在除了知道怎么来的、这么用,还要知道每一步是怎么来的,为什么这么用。


先说页面,

比如,页面里面有 HTML 和 CSS,最后会把页面展示给我们,但是在展示给我们的时候叫页面已经绘制完成了


什么是绘制页面?

浏览器里面有一个渲染引擎,它会一行一行的绘制页面,

一行就是以一个像素的高度为单位,一行一行的这么绘制,

就像 3D 打印一样,一层一层把东西打印完,

绘制页面也是一样,它会按照 HTML、CSS 语法去绘制页面。


页面上有一个 div 元素,一个 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>


css 是怎么和 div 元素联系到一起的?

怎么的一个加载顺序?

HTML 和 CSS 是怎么执行的呢?


在系统内核的内部,它不认识我们写的 div 和 css,他不会认识代码的,

内核是不会让它俩产生链接的,内核是怎么办的呢?


浏览器里面的内核,会对页面进行一步一步的检索,

首先,先识别我们写的 HTML 代码

然后会把一大堆 HTML 代码(比如写了一大堆标签),形成一个叫 domTree(dom树)的东西,

<div></div>

<span></span>

<strong>

  <em></em>

</strong>


1、domTree

第一个概念叫 dom 树(domTreed),

dom 树会把整个页面的 html 代码一行一行去识别,识别后挂到一颗树形的结构上,

树的顶端是 html 标签,树的左侧是 head 标签,右侧是 body 标签

未标题-1.png

浏览器会把 html 代码每一个节点,放到树形结构对应的位置里面去,

也就是说根据节点的排列方式绘制出一个 dom 树,叫 dom 节点的树形结构,

而且绘制 dom 树符合一个原则,叫深度优先原则。


什么叫深度优先?

深度优先就一条道走到黑,

看完 html 完之后,会先看左侧的 head,然后再看 head 里面有什么东西,

head 里面有 meta 绘制 meta,有 title 绘制 title,

一条枝干走到头之后,再反过来,看另一条枝干 body,深度优先原则。


怎么形成一个 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


2、cssTree

domTree(dom树)生成之后什么都不干,等着,

等 cssTree 树形成,


css 树就是系统根据我们写的 css,也形成跟 dom 树类似的一个树叫 css 树,

跟 dom 节点都是对应的,css树跟dom树都一样深度优先


css 树生成完之后,它会和dom树拼到一起,生产一个新的树叫 randerTree

 domTree + cssTree = randerTree 


3、randerTree

randerTree 形成完了以后,渲染引擎才会真正的开始绘制页面,

按照 randerTree 里面每一条的规则去绘制页面,

每一条节点应该怎么绘制,在什么样的位置出现,符合什么样的原则。


4、reflow 重排

在绘制页面的过程中,

js 可以动态的改变 dom 结构,和间接的影响 css,

由于 randerTree 是页面最后绘制的依据,如果改变一个 dom 的结构,删除一个或增加一个dom节点,dom 树就变了,

dom 树一变,randerTree 就要重新去构建。


如果 randerTree 重新构建,这个页面就要重新绘制,从第一行绘制到最后,这样会浪费效率,

所以 dom 优化的前提是,尽量减少 dom 节点的添加、删除这种操作,

即使操作的话,最好一次性的操作完,

不要一会操作一次,这样反复做,会反复进行 reanderTree 构建,

这种 reanderTree 的重建,我们叫 reflow 重排或者重构,dom 操作里面重构是效率最低的。


哪几种情况会触发重构呢?

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 重绘


5、repaint 重绘

比如给一个 dom 节点改变背景颜色,但凡改一个东西,reanderTree 都会重新构建的,

只不过是基于什么进行重新构建,如果是基于 css 的颜色重新构建的话,不会全把 reanderTree 改变,

会先把 css 树的一部分改变了,然后在对应的 reanderTree 上面,把那一部分进行改变,

也就是说影响比较小,重绘的只是这一部分,不会是整个页面都重绘,


所以 repaint 浪费的效率就很小,是可以接受的,

比如改字体颜色,改背景图片,背景图片的位置随便改,不会影响后续元素,

但是改字体宽高、字体大小,整个页面都会受到影响,就会进行 reflow 重构



Leave a comment 0 Comments.

Leave a Reply

换一张