虚拟 DOM 和 DOM diff

137 阅读2分钟

虚拟DOM是什么

虚拟DOM其实就是一棵以JavaScript对象 (VNode节点) 作为基础的树,用对象属性来描述节点,实际上它只是一层对真实DOM的抽象。最终可以通过一系列操作使这棵树映射到真实环境上。

在JavaScript里面,虚拟DOM表现为一个Object对象。并且最少包含标签名 (tag)、属性 (attrs) 和子元素对象 (children) 三个属性。不同的框架对这三个属性的名命可能会有差别。

不过总的来讲,虚拟DOM对象的节点跟DOM Tree每个位置的属性一一对应的,因为人们创造出虚拟DOM就是为了更好地将虚拟节点渲染到视图上,也就是把虚拟DOM变成真实的DOM节点,提高视图的渲染性能。

虚拟DOM的优点

1. 减少dom操作:

减少频率:虚拟DOM可以将多次操作合并为一次操作,比如你添加1000个节点,却是一个接一个操作的。 减少范围:虚拟DOM借助DOM diff可以把多余的操作省掉,比如你添加1000个节点,其实只有10个是新增的。

2. 跨平台:

虚拟DOM不仅可以变成DOM,还可以变成小程序、iOS 应用、安卓应用,因为虚拟DOM本质上只是一个JS对象。

虚拟DOM的缺点

需要额外的创建函数,如createElement或h,但可以通过JSX来简化成XML写法。

DOM diff是什么

  • DOM diff就是一个函数,我们称之为patch;
  • patches = patch(oldVNode, newVNode);
  • patches就是要运行的DOM操作,可能长这样:
[
  {type: 'INSERT', vNode: ... },
  {type: 'TEXT'vNode: ... },
  {type: 'PROPS', propsPatch: [...]}
]

DOM diff可能的大概逻辑

• Tree diff

  1. 将新旧两棵树逐层对比,找出哪些节点需要更新;
  2. 如果节点是组件就看 Component diff;
  3. 如果节点是标签就看 Element diff。

• Component diff

ü如果节点是组件,就先看组件类型; ü类型不同直接替换(删除旧的); ü类型相同则只更新属性; ü然后深入组件做 Tree diff(递归)。

• Element diff

ü如果节点是原生标签,则看标签名; ü标签名不同直接替换,相同则只更新属性; ü然后进入标签后代做 Tree diff(递归)。

DOM diff的优点

DOM diff算法会对比 oldNode 与 newNode 的区别,从而减少不必要的渲染

DOM diff的缺点(key)

DOM diff在同层级对比中有bug。造成页面渲染错误。

同一层级的一组节点可以通过唯一的id进行区分, 所以可以给节点设定唯一的key。从而消除bug。

key只能是number和string类型,一定不要用index作为key值。