diff算法不是vue专用
- 必要性,lifecycle.js - mountComponent()
- 执行方式,patch.js - patchVnode()
- 高效性,patch.js - updateChildren()
必要性
一个组件执行一次mount对应一个watcher,为了精确的定位到到底是哪个变化了,这时候diff就很必要了
执行方式
patchVnode是diff的开始,整体策略:深度优先,同层比较,递归操作,先找最里层的vnode
递归
新节点有孩子
清空老节点文本
创建孩子并追加
老节点有孩子,删除即可
老节点存在文本,清空
双方都是文本节点,跟新文本
算法的核心优化点在updateChildren
头尾指针调整
接下来是头尾比较4种情况
两个开头相同
索引向后移动一位
老的开始和新的结束相同,除了打补丁之外还要移动到队尾
如果在首尾都没有找到相同节点,则会进行遍历查询,拿出新数组的首个去老数组中进行查找如果找到做相对应的操作,如果没有找到则认为是一个新增节点,我们会去创建新元素,如果找到了直接进行更新打补丁,还要移动到队首
高效性
总结
- diff算法是虚拟DOM技术的必然产物:通过新旧虚拟DOM做对比,(即diff),将变化的地方更新在真实的DOM上,另外,也需要diff高效的执行对比的过程,从而降低时间复杂度为O(n).
- vue 2.x中为了降低Watcher粒度,每个组件只有一个Watcher与之对应,只有引入diff才能精确找到发生变化的地方
- vue中diff执行的时刻是组件实例执行其更新函数时,他会对比上一次渲染结果oldVnode和新的渲染结果newVnode,此过程称为patch
4.diff过程整体遵循深度优先,同层比较的策略;两个节点之间的比较会根据他们是否拥有子节点或者文本节点做不同的操作,比较两组子节点是算法的重点,首先假设头尾节点可能相同,做4次对比尝试,如果没有找到相同的节点才按照通用方式遍历查找,查找结束再按照情况处理剩下的节点,借助key通常可以非常精确的找到相同的节点,因此整个patch过程会非常的高效