【源码】vue2 patch源码刨析
【公司内部分享】探索Vue.js框架内部原理和实现机制,旨在理解其核心概念和技术细节,以便更好地应用和定制Vue.js。
相关文章
- vue3 为什么说渲染、更新更快、内存占用更少
- vue3 为什么说打包体积更小
- vue3 为什么说跨平台能力更强
- vue2 项目结构与架构设计介绍
- vue2 变化侦测与异步更新源码刨析
- vue2 模板编译源码刨析
- vue2 patch源码刨析
- vuex4 源码浅析
环境
- vue:v2.6.1
vue2 patch源码刨析
一、什么是虚拟DOM
什么是虚拟DOM
本质就是一个通过状态树来描述DOM节点树的普通js对象
如何创建虚拟DOM
二、为什么要引入虚拟DOM
- 1:虚拟DOM是时代发展的产物,从过去JQuery时代的命令式操作DOM转为声明式操作DOM已经势在必行。
- 2:由于虚拟DOM是抽象描述节点间的状态关系,不依赖真实的平台环境,因此还具备跨平台的优势。
基本原理
- 1:使用栈维护AST层级,遇到开始标签则把当前节点推入栈,遇到结束标签则把当前节点弹出栈
- 2:四个钩子函数(start,end,chars,comment)
工作流程
每截取一小段字符串,就会根据截取出来的字符串类型触发不同的钩子函数,直到模板字符串截空停止运行
三、Patch 的工作流程
基本规则
- 1:新节点不存在,执行删除
- 2:旧节点存在、新节点存在、执行diff(重点)
- 3:旧节点存在,新节点不存在、执行删除
如何确认为同一节点
Key相同、当前节点的标签名相同、isComment相同(注释节点属性)、data都有或都没有定义、当标签是input的时候type相同
四、PatchVnode 的工作流程
基本规则
- 1:相同节点或都是静态节点直接退出
- 2:新旧都有文本节点且不一样则修改文本,否则执行新增或删除
- 3:新旧都有子节点且不一样则直接updateChildren(DIFF),否则执行新增或删除
五、Diff基本规则与目的
基本规则
- 1、只在同层级之间进行比较,不会跨层级比较,时间复杂度只有O(n)
- 2、优先深度遍历所有节点进行比较,直到完成再去比较当前节点的下一个同层级节点
目的
- 为了减少更新量,找到最小差异部分DOM,进行patch
六、DIFF的工作流程
差异
- 1)新增节点11
- 2)删除节点8
- 3)1,10节点未变化
- 4)2、3、4、5、6、7节点位置变化
Step1 处理头头\尾尾同类节点
即oldStart和newStart ,以及oldEnd和newEnd指向同类节点的情况,如图中的节点1和节点10,移动之后标记该节点,若节点有更新则同步进行更新,同时将newStart、oldStart各后移1位,newEnd、oldEnd各前移一位
Step2 处理头尾\尾头同类节点
即oldStart和newEnd,以及oldEnd和newStart指向同类节点的情况,如图中的节点2和节点9,移动之后标记该节点,若节点有更新则同步进行更新,同时将newStart、oldStart各后移1位,newEnd、oldEnd各前移一位
Step3 处理新增的节点
此时newStart来到了节点11的位置,在oldVdom中找不到节点11,说明它是新增的,那么就创建一个新的节点,插入DOM树,插到oldStart指向的节点(即节点3)前面
Step4 处理更新的节点
此时newStart来到了节点7的位置,在oldVdom中能找到它但不在指针位置,说明它是移动的,那么将节点7移到oldStart指向的节点(即节点3)前面,与此同时将节点标记为已处理
Step5 重复步骤1
此时我们看到了令人欣慰的一幕,newStart和oldStart又指向了同一个节点(即都指向节点3),此时再按照(Step1)中的做法只需移动指针即可,3、4、5、6都同样处理
Step6 处理删除的节点
此时newStart跨过了newEnd,它们相遇了!而oldStart和oldEnd还没有相遇,说明这2个指针之间的节点(包括它们指向的节点,即图中的节点7、节点8)是此次更新中被删掉的节点
Tip
还记得前面我们对节点7做了标记吗,标记的目的是告诉Vue它已经处理过了,是需要出现在新DOM中的节点,不要删除它,所以在这里正在删除的只有节点8
DIFF完成
整个过程是逐步找到更新前后vdom的差异,然后将差异反应到DOM树上(也就是patch),提醒:Vue的patch是即时的,并不是打包所有修改最后一起操作DOM(React则是将更新放入队列后集中处理)[ PS:现代浏览器对这样的DOM操作做了优化,不要担心 ]