1.虚拟DOM(Virtual Document Object Model)
- DOM的本质是什么:用JS表示的UI元素
- DOM和虚拟DOM的区别:
- DOM是由浏览器中的JS提供功能,所以我们只能人为的使用 浏览器提供的固定的API来操作DOM对象;
- 虚拟DOM:并不是由浏览器提供的,而是我们程序员手动模拟实现的,类似于浏览器中的DOM,但是有着本质的区别;
- 为什么要实现虚拟DOM:
- 什么是React中的虚拟DOM:程序员使用js对象模拟出来的DOM。
- 虚拟DOM的目的:通过对比新旧的两棵模拟DOM树,然后通过diff算法找出这两棵树的差异,只对有更新的DOM进行按需更新,没有改变的DOM则不做改动。
只更新改变的DOM
与整棵DOM树重建
相比,前者使用虚拟DOM刷新UI界面就更加高效了。
2. DIff算法
Web 界面由 DOM 树来构成,当其中某一部分发生变化时,其实就是对应的某个 DOM 节点发生了变化。在 React 中,构建 UI 界面的思路是由当前状态决定界面。前后两个状态就对应两套UI界面,然后由 React 的Diff 算法来比较两个界面的区别。
2.1 不同节点类型的比较
为了在树之间进行比较,我们首先要能够比较两个节点,在 React 中即比较两个虚拟 DOM 节点,当两个节点不同时,应该如何处理。这分为两种情况:
(1)节点类型不同
(2)节点类型相同,但是属性不同。
当在树中的同一位置前后输出了不同类型的节点,React 直接删除前面的节点,然后创建并插入新的节点。假设我们在树的同一位置前后两次输出不同类型的节点。
renderA: <div />
renderB: <span />
=> [removeNode <div />], [insertNode <span />]
当一个节点从 div 变成 span 时,简单的直接删除 div 节点,并插入一个新的 span 节点。这符合我们对真实 DOM 操作的理解。
需要注意的是,删除节点意味着彻底销毁该节点,而不会在后续的比较中再去看是否有另外一个节点等同于该删除的节点
。如果该删除的节点之下有子节点,那么这些子节点也会被完全删除,它们也不会用于后面的比较。这也是算法复杂能够降低到 O(n)的原因。
上面提到的是对虚拟 DOM 节点
的操作,而同样的逻辑也被用在 React 组件
的比较,例如:
renderA: <Header />
renderB: <Content />
=> [removeNode <Header />], [insertNode <Content />]
当 React 在同一个位置遇到不同的组件时,也是简单的销毁第一个组件,而把新创建的组件加上去。这正是应用了第一个假设,不同的组件一般会产生不一样的 DOM 结构,与其浪费时间去比较它们基本上不会等价的 DOM 结构,还不如完全创建一个新的组件加上去。
由这一 React 对不同类型的节点的处理逻辑我们很容易得到推论,那就是 React 的 DOM Diff 算法实际上只会对树进行逐层比较,如下所述。