Vue源码浅读

Vue3上线很久了,一直想花时间看看响应式怎么实现的,和Vue2的思路有区别吗,这周末花了点时间debug和看源码,大概了解了Vue3的更新链路,写个小笔记记录一下,可能有些细节缺失,或者如果有写得不太对的请多包涵

V2版本

在学习Vue3的源码之前,先了解一下Vue2的双向绑定是怎么实现的

V2版本作为Vue的经典版本,引入了多个核心概念:

  • Vue实例:代表着组件的实例化对象。
  • Data:存放在组件内的数据。
  • VNode:作为模板的表现形式。
  • Dep:负责依赖收集,管理Data中的键与Watcher之间的关系。
  • Watcher:监测数据变化的观察器,在数据更新时Dep会通知Watcher进行更新。

V2版本的主要链路可分为以下三个步骤:

链路1. Vue实例初始化

在初始化阶段,Vue会遍历Data中的所有对象,利用Object.defineProperty对对象的键进行代理,从而管理键的get和set方法。每个键会生成一个对应的Dep实例,用于管理依赖关系。

链路2. 挂载(Mount)链路

这一阶段涉及获取Vue实例、生成Watcher实例以及首次执行更新函数updateComponent

源码里,一个vm实例生成一个Watcher实例,并传入更新函数:updateComponent

生成一个Watcher实例之后,构造函数里,会执行一次Watcher的get方法依赖收集的核心逻辑就在这个get方法里

scss 复制代码
pushTarget(this) // 最终是执行Dep.target = this
...
this.getter.call(vm, vm) // 最终会执行组件的render函数
// render函数会获取data,触发Data上的key的get方法,从而触发依赖收集
...
popTarget() // 将Dep.target置为null

执行完之后,最终一个key的Dep实例,会管理一个或者多个Watcher

链路3. 数据更新流程

当数据更新时,会执行到链路1中为键定义的setter方法。此时找到相关的Dep实例,通知关联的Watcher进行更新,Watcher更新,会将watcher放到更新队列中,按队列执行watcher.run(),看到最终会执行watcher的get方法,也会执行收集依赖的逻辑,不过收集依赖是有去重的,不会重复收集

探索V3版本

V3版本对Vue的实现进行了更新和改进,在源码中有一些新的变化。

链路1. 创建Vue实例

在V3版本中,createApp方法生成一个app对象,这个对象在源码里看到不属于任何类,只是定义一个对象和对象上的方法,直接返回

链路2. 数据代理和依赖收集

在V3版本中,使用ref(value)reactive(object)定义数据。每个数据都会生成一个RefImpl实例,利用proxy对数据进行代理,并在内部实现依赖管理。getter方法类似V2版本的Dep,存在track函数用于依赖收集;而setter方法中则调用trigger函数,在数据更新时触发依赖更新。

链路3. 挂载流程

整个链路比较长,大致流程是,第一次会执行到setupStatefulComponent,最终会执行函数的setup方法,但是这时候没有进行依赖收集

继续往下看,执行到setupRenderEffect,可以看到每个组件实例都会生成一个ReactiveEffect实例,会执行ReactiveEffect实例的run方法,依赖收集的核心逻辑就在这个run方法

arduino 复制代码
// 1、activeEffect赋值this(当前的ReactiveEffect实例),shouldTrack设置为true
// 2、执行`componentUpdateFn`
// 3、执行`renderComponentRoot`,最终会执行到组件的render函数,会使用ref定义的数据
// 4、因为activeEffect有值,并且shouldTrack为true,所以会触发依赖收集
// 5、依赖收集,会将`RefImpl`实例的dep属性和activeEffect做一个关联
// 即一个dep可能会管理多个ReactiveEffect`实例
// 6、依赖收集会去重

链路4. 数据更新流程

当有数据更新的时候,会触发RefImpl实例value的setter方法,取出对应的dep记录的effect,最终执行effect.scheduler()或者effect.run(),这两个方法最终都会执行componentUpdateFn函数,执行组件的render函数,重新走一遍收集依赖的流程。

因为同一份依赖收集过,所以不会收集重复的依赖

相关推荐
染指11101 小时前
103.RAG-LLamaIndex后端rag问答-聊天接口
前端·javascript·vue.js·人工智能
单线程_019 小时前
从案例分析 Vue3 Tokenizer+Parser 源码三
前端·javascript·vue.js
jay神10 小时前
【计算机毕业设计】基于SpringBoot的程序教学辅助系统
java·前端·vue.js·spring boot·后端·毕业设计·课程设计
小磊哥er11 小时前
深入解构Claude Code - 第 8 篇 · 数据放哪、钱怎么算
javascript·ai编程
kyriewen12 小时前
我装了30多个Skill,给AI安排了8个岗位
前端·javascript·ai编程
默_笙14 小时前
🔥 让 AI 帮我写完整个 Next.js 博客:框架就是 AI 的"上下文 buff"
前端·javascript
OpenTiny社区16 小时前
从流式消息到多会话:TinyRobot Kit 如何组织 AI 对话数据层
vue.js
喵本喵叁肆17 小时前
06-M6-部门过滤与综合研判-从问答机到研判助手
前端·javascript·jquery
卤蛋fg618 小时前
vue表格组件 vxe-table 鼠标滑动表头选择整列与选择整行的配置详解
vue.js
এ慕ོ冬℘゜18 小时前
JavaScript学习心得:从只会语法,到真正会写业务逻辑
开发语言·javascript·ecmascript