【Vue】浅谈 Vue 的 diff 算法(未完成)
前言
diff 是 Vue 执行种的一个重要过程,是深入学习 Vue 时不容忽视的部分。
本篇文章暂时仅分析 Vue2 的 diff 基本原理,后续考虑补充源码分析和其他框架,如 React、Vue3 的 diff 相关内容,视情况而定。
是什么
在学习 Diff 算法之前,我们需要先了解几个概念。
1. Virtual DOM
虚拟 DOM(Virtual DOM)是一种将浏览器 DOM 的信息存储在 JavaScript 内存中的方法,是以 JavaScript 对象表示的抽象化的 DOM。
相比于操作 DOM,通过 JavaScript 操作 Virtual DOM 的开销要小得多。
2. VNode
Virtual DOM 为 DOM 的抽象表示。相同的,VNode 就是是 DOM 节点的抽象表示,是 Virtual DOM 的节点。
VNode 同样也是一个 JavaScript 对象,包括这个 DOM 节点的所有属性内容。
3. AST
AST(Abstract Syntax Tree),即抽象语法树,是源代码语法结构的一种抽象表示(树状形式)。树上的每个节点均代表源代码的一种结构。
Vue 通过编译将模板转换为 AST ,再将 AST 转换为渲染函数,执行渲染函数得到新的 VNode,将其与旧的 VNode 比对,对更改的部分进行更新、替换,最后渲染到页面上。
这个比对新旧 VNode,并进行更新、替换的过程就是 diff 的过程。diff 的结果是得到一个新的 VNode 树,用于页面渲染。
为什么
我们不妨设想一下不进行 Diff 的情况。这种情况下我们每次更新页面数据,都需要对页面整体的 DOM 进行渲染,这个消耗是非常大的。
而 Diff 的作用,就是找到新旧 DOM 的最小差异,尽量减少更新量,最大程度地降低渲染消耗。
那么,Vue 使用 Diff 的理由也就显而易见了,就是为了减少性能消耗。
基本逻辑
传统的 Diff 算法会递归处理每一个节点,计算量非常大。
将两颗树中所有的节点一一对比需要 O(n²)的复杂度,在对比过程中发现旧节点在新的树中未找到,那么就需要把旧节点删除,删除一棵树的一个节点(找到一个合适的节点放到被删除的位置)的时间复杂度为 O(n),同理添加新节点的复杂度也是 O(n),合起来 diff 两个树的复杂度就是 O(n³)
而 React 和 Vue2 的 diff 算法规则大致相同,仅在同级的 VNode 之间做比较计算,递归进行,最终实现整个 DOM 树的更新。
diff 算法一般包括几个主要的逻辑,以 3 层嵌套的 DOM 为例:
1 | // 简化vdom结构如下 |
图示如下
1. 不同节点类型的比较
我们想在二级节点 branch-A 下追加一个三级子节点 leaf-A-2,如下图所示:
这种情况仅生成节点 leaf-A-2 并插入到 branch-A 的子节点列表。