vue虚拟dom解读

1. 浏览器渲染页面的过程

输入url地址–>访问dns域名解析服务器解析url地址为ip地址–>找到该ip地址下的服务器的web站点管理工具->根据端口号访问对应的project文件夹–>根据url地址传回相应的代码
比如传回index.html
浏览器收到index.html,就开始对其自上而下解析

  1. 用HTML分析器,解析HTML元素,构建一颗DOM树(标记化和树构建)

DOM树结构和HTML标签一一对应。
DOM树在构建的过程中可能会被CSS和JS的加载而执行阻塞。
display:none 的元素也会在DOM树中。
注释也会在DOM树中。
script标签会在DOM树中

  1. 用CSS分析器,分析CSS文件和元素上的inline样式,生成页面的样式表。也就是构建cssom。

cssom和dom树同时构建

  1. 将DOM树和样式表,关联起来,构建一颗Render树(这一过程又称为Attachment)。浏览器会先从DOM树的根节点开始遍历每个可见节点,让后对每个可见节点找到适配的CSS样式规则并应用。每个DOM节点都有attach方法,接受样式信息,返回一个render对象(又名renderer)。这些render对象最终会被构建成一颗Render树

Render Tree和DOM Tree不完全对应。
display:none的不在render tree里,visibility:hidden的在render treel里

  1. 有了Render树,浏览器开始布局,为每个Render树上的节点确定一个在显示屏上出现的精确坐标

float元素,absoulte元素,fixed元素会发生位置偏移
我们常说的脱离文档流,其实就是脱离render tree

  1. 渲染树绘制,调用每个节点paint方法
    流程如下
    在这里插入图片描述
    【link标签和script标签会阻塞渲染吗】
    自上而下解析,遇到任何样式(link、style)和脚本(script)都会阻塞。
  • css加载不会阻塞html文件的解析,但会阻塞dom的渲染,浏览器将在 CSSOM 构建完毕前不会渲染任何已处理的内容
  • css加载会阻塞后面js语句的执行
  • js会阻塞html的解析和渲染
    js不仅可以读取修改dom,还可以读取修改cssom属性,因此CSS解析与script的执行互斥。
    所以,在引入顺序上,CSS 资源先于 JavaScript 资源。所以一般都把css放head标签,js放body的底部。

2. 重绘和回流

reflow(回流):当浏览器发现某个部分发生了变化从而影响了布局,这个时候就需要倒回去重新渲染,大家称这个回退的过程叫 reflow。 常见的reflow是一些会影响页面布局的操作,诸如Tab,隐藏等。reflow 会从 html 这个 root frame 开始递归往下,依次计算所有的结点几何尺寸和位置,以确认是渲染树的一部分发生变化还是整个渲染树。reflow几乎是无法避免的,因为只要用户进行交互操作,就势必会发生页面的一部分的重新渲染,且通常我们也无法预估浏览器到底会reflow哪一部分的代码,因为他们会相互影响。

repaint(重绘): repaint则是当我们改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸和位置没有发生改变。

3. vue的优点

除了开发方便,最主要的是virtual dom,减少对真实dom的操作。

3.1 操作真实dom的代价

用传统开发模式,原生JS操作DOM时,每一次浏览器都会从构建DOM树开始从头到尾执行一遍流程。在一次操作中,我需要更新10个DOM节点,浏览器收到第一个DOM请求后并不知道还有9次更新操作,因此会马上执行流程,最终执行10次。例如,第一次计算完,紧接着下一个DOM更新请求,这个节点的坐标值就变了,前一次计算就白计算了。频繁操作会出现页面卡顿,影响用户体验。vue里的virtual dom就减少了对真实dom的频繁操作

3.2 虚拟dom的好处

若一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量。所以,用JS对象模拟DOM节点的好处是,页面的更新可以先全部反映在JS对象(虚拟DOM)上,操作内存中的JS对象的速度显然要更快,等更新完成后,再将最终的JS对象映射成真实的DOM,交由浏览器去绘制

3.4 虚拟dom的创建及最终转化为真实dom

比如:这是一个真实dom
在这里插入图片描述
用js模拟虚拟dom:
在这里插入图片描述
Element方法如下,传参传入的是该节点(比如div),属性(比如class),子节点在这里插入图片描述
这样就形成了一个js虚拟dom树。
最终还是要将虚拟dom映射成真实dom,用如下方法,这里就是js原生的对dom操作方法
在这里插入图片描述
既然已经完成了创建虚拟dom,并可最终将虚拟dom转化为真实dom,这样中间所有的更新都可以先反应到虚拟DOM上,最终再转为真实dom,这里就要用到diff算法

3.3 diff算法

在实际代码中,会对新旧两棵树进行深度的遍历,每个节点都会有一个标记。每遍历到一个节点就把该节点和新的树进行对比,如果有差异就记录到一个对象中。
拿之前创建完的虚拟dom举例
在这里插入图片描述

  1. 如上如果只把第二行改为’div’,这属于replace,节点类型变了,例如p变成了div。直接将旧节点卸载并装载新节点。
  2. 节点类型一样,仅仅属性或属性值变了。我们将这个过程称之为PROPS。此时不会触发节点卸载和装载,而是节点更新。
  3. 文本变了,文本对也是一个Text Node,也比较简单,直接修改文字内容就行了,我们将这个过程称之为TEXT。
  4. 移动/增加/删除 子节点,我们将这个过程称之为REORDER。看一个例子,在A、B、C、D、E五个节点的B和C中的BC两个节点中间加入一个F节点。
    在这里插入图片描述
    在这里插入图片描述
    最简单的做法是遍历每一个新虚拟DOM的节点,与旧虚拟DOM对比相应节点对比,在旧DOM中是否存在,不同就卸载原来的按上新的。这样会对F后边每一个节点进行操作。卸载C,装载F,卸载D,装载C,卸载E,装载D,装载E。效率太低
    如果我们为数组或枚举型元素增加上key后,它能够根据key,直接找到具体位置进行操作,效率比较高,这样就是为什么v-for要定义:key
    虚拟DOM有了,Diff也有了,现在就可以将Diff应用到真实DOM上了。深度遍历DOM将Diff的内容更新进去。

猜你喜欢

转载自blog.csdn.net/qq_33712668/article/details/100161111