前置概念
- vdom:多个虚拟元素节点组合成的树状结构
- vnode:某一个虚拟元素节点
- 挂载:将虚拟DOM节点渲染成真实DOM节点的过程
一、渲染器的设计
首先我们要区分vue当中两个概念,一个是渲染器(renderer),一个是渲染(render)。
前者renderer,渲染器的作用是将我们的vdom转化成真实的DOM元素来呈现。
后者render,渲染函数的作用是将我们的vnode添加并且挂载到真实DOM容器下。
1.1 渲染器内部属性和方法
1、:抽离依赖环境方法,使其变成自定义渲染器
2、:将节点渲染到真实的元素当中
3、:挂载、更新节点
4、:挂载节点为真实的元素
5、:挂载、更新属性
6、:更新节点
7、:更新子节点
1.2 核心代码
1.3 整体执行流程图
二、Diff算法
2.1 简单Diff算法
Diff算法的引出:
对于和不同的进行更新操作,最容易想到的就是将旧的子节点全部卸载,然后重新挂载最新的子节点。但是对于这个操作会有很大的性能开销,因为直接操作Dom了。
优化和改进:
对于更新子节点情况,有时候可能只是单纯顺序不一样,因此其实可以通过去判断的去判断,但是这里也有一个缺陷,就是我们的children值可能是不同的,因此引入去确定是否可以复用当前的这个DOM节点,然后再去判断移动位置、卸载和挂载节点。
执行流程:
- 拿新的一组子节点中的节点去旧的一组子节点中去查找。如果找到,更新节点,记录下最大索引值,同时标记当前节点已存在,如果索引呈现递增的形式就是不需要移动,否则就要移动
- 当前节点不存在的时候,需要找到合适的位置进行挂载节点,如果是中间的节点,那么找之前的节点的兄弟节点,这个兄弟节点的之前位置就是正确的,若是首个节点,那么挂载在当前容器的第一个节点之前
- 当新的一组子节点遍历完成,遍历旧的一组子节点,检查是否容器有多余的旧节点需要卸载
核心代码:
2.2 双端Diff算法
优势:
执行的DOM移动操作次数更少
按照上面双端Diff算法的执行过程,那么这两种情况下,均会跳出执行的循环,因此我们需要在循环外部再做一些操作
核心代码:
2.3 快速Diff算法
执行流程:
- 处理两组子节点的前置节点和后置节点
- 创建数组即索引数组来获得最长递增子序列来判断剩余的节点哪些需要进行移动()
核心代码:
2.4 总结
Diff算法根本的核心:
- 判断是否有节点需要移动,以及如何移动
- 找到哪些需要被添加或者移除的节点
三个Diff算法的速度性能:
简单Diff < 双端Diff < 快速Diff