千家信息网

怎么理解Vue 3.0的响应式系统

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,这篇文章主要介绍"怎么理解Vue 3.0的响应式系统",在日常操作中,相信很多人在怎么理解Vue 3.0的响应式系统问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"怎么理
千家信息网最后更新 2026年11月01日怎么理解Vue 3.0的响应式系统

这篇文章主要介绍"怎么理解Vue 3.0的响应式系统",在日常操作中,相信很多人在怎么理解Vue 3.0的响应式系统问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"怎么理解Vue 3.0的响应式系统"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一个基本的例子

Vue 3.0 的响应式系统是独立的模块,可以完全脱离 Vue 而使用,所以我们在 clone 了源码下来以后,可以直接在 packages/reactivity 模块下调试。

  1. 在项目根目录运行 yarn dev reactivity,然后进入 packages/reactivity 目录找到产出的 dist/reactivity.global.js 文件。

  2. 新建一个 index.html,写入如下代码:

     

3. 在浏览器打开该文件,于控制台执行 state.count++,便可看到输出 set count to 1。

在上述的例子中,我们使用 reactive() 函数把 origin 对象转化成了 Proxy 对象 state;使用 effect() 函数把 fn() 作为响应式回调。当 state.count 发生变化时,便触发了 fn()。接下来我们将以这个例子结合上文的流程图,来讲解这套响应式系统是怎么运行的。

初始化阶段

在初始化阶段,主要做了两件事。

  1. 把 origin 对象转化成响应式的 Proxy 对象 state。

  2. 把函数 fn() 作为一个响应式的 effect 函数。

首先我们来分析第一件事。

大家都知道,Vue 3.0 使用了 Proxy 来代替之前的 Object.defineProperty(),改写了对象的 getter/setter,完成依赖收集和响应触发。但是在这一阶段中,我们暂时先不管它是如何改写对象的 getter/setter 的,这个在后续的"依赖收集阶段"会详细说明。为了简单起见,我们可以把这部分的内容浓缩成一个只有两行代码的 reactive() 函数:

export function reactive(target) {    const observed = new Proxy(target, handler)    return observed  }

完整代码在 reactive.js。这里的 handler 就是改造 getter/setter 的关键,我们放到后文讲解。

接下来我们分析第二件事。

当一个普通的函数 fn() 被 effect() 包裹之后,就会变成一个响应式的 effect 函数,而 fn() 也会被立即执行一次。

由于在 fn() 里面有引用到 Proxy 对象的属性,所以这一步会触发对象的 getter,从而启动依赖收集。

除此之外,这个 effect 函数也会被压入一个名为"activeReactiveEffectStack"(此处为 effectStack)的栈中,供后续依赖收集的时候使用。

来看看代码(完成代码请看 effect.js):

export function effect (fn) {    // 构造一个 effect    const effect = function effect(...args) {      return run(effect, fn, args)    }    // 立即执行一次    effect()    return effect  }  export function run(effect, fn, args) {    if (effectStack.indexOf(effect) === -1) {      try {        // 往池子里放入当前 effect        effectStack.push(effect)        // 立即执行一遍 fn()        // fn() 执行过程会完成依赖收集,会用到 effect        return fn(...args)      } finally {        // 完成依赖收集后从池子中扔掉这个 effect        effectStack.pop()      }    }  }

至此,初始化阶段已经完成。接下来就是整个系统最关键的一步——依赖收集阶段。

依赖收集阶段

这个阶段的触发时机,就是在 effect 被立即执行,其内部的 fn() 触发了 Proxy 对象的 getter 的时候。简单来说,只要执行到类似 state.count 的语句,就会触发 state 的 getter。

依赖收集阶段最重要的目的,就是建立一份"依赖收集表",也就是图示的"targetMap"。targetMap 是一个 WeakMap,其 key 值是当前的 Proxy 对象 state代理前的对象origin,而 value 则是该对象所对应的 depsMap。

depsMap 是一个 Map,key 值为触发 getter 时的属性值(此处为 count),而 value 则是触发过该属性值所对应的各个 effect。

还是有点绕?那么我们再举个例子。假设有个 Proxy 对象和 effect 如下:

const state = reactive({    count: 0,    age: 18  })  const effecteffect1 = effect(() => {    console.log('effect1: ' + state.count)  })  const effecteffect2 = effect(() => {    console.log('effect2: ' + state.age)  })  const effecteffect3 = effect(() => {    console.log('effect3: ' + state.count, state.age)  })

那么这里的 targetMap 应该为这个样子:

这样,{ target -> key -> dep } 的对应关系就建立起来了,依赖收集也就完成了。代码如下:

export function track (target, operationType, key) {    const effect = effectStack[effectStack.length - 1]    if (effect) {      let depsMap = targetMap.get(target)      if (depsMap === void 0) {        targetMap.set(target, (depsMap = new Map()))      }      let dep = depsMap.get(key)      if (dep === void 0) {        depsMap.set(key, (dep = new Set()))      }      if (!dep.has(effect)) {        dep.add(effect)      }    }  }

弄明白依赖收集表 targetMap 是非常重要的,因为这是整个响应式系统核心中的核心。

响应阶段

回顾上一章节的例子,我们得到了一个 { count: 0, age: 18 } 的 Proxy,并构造了三个 effect。在控制台上看看效果:

效果符合预期,那么它是怎么实现的呢?首先来看看这个阶段的原理图:

当修改对象的某个属性值的时候,会触发对应的 setter。

setter 里面的 trigger() 函数会从依赖收集表里找到当前属性对应的各个 dep,然后把它们推入到 effects 和 computedEffects(计算属性) 队列中,最后通过 scheduleRun() 挨个执行里面的 effect。

由于已经建立了依赖收集表,所以要找到属性所对应的 dep 也就轻而易举了,可以看看具体的代码实现:

export function trigger (target, operationType, key) {    // 取得对应的 depsMap    const depsMap = targetMap.get(target)    if (depsMap === void 0) {      return    }    // 取得对应的各个 dep    const effects = new Set()    if (key !== void 0) {      const dep = depsMap.get(key)      dep && dep.forEach(effect => {        effects.add(effect)      })    }    // 简化版 scheduleRun,挨个执行 effect    effects.forEach(effect => {      effect()    })  }

这里的代码没有处理诸如数组的 length 被修改的一些特殊情况,感兴趣的读者可以查看 vue-next 对应的源码,或者这篇文章,看看这些情况都是怎么处理的。

至此,响应式阶段完成。

到此,关于"怎么理解Vue 3.0的响应式系统"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

对象 阶段 函数 系统 代码 属性 例子 接下来 就是 学习 时候 重要 关键 情况 效果 文件 更多 核心 模块 池子 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 科技互联网公司装修 互联网科技小贷 成都互联网科技公司 朗涯互联网科技 顺玮阁互联网科技 上海亿帐通互联网科技 哈尔滨新华互联网科技 科技类公司包括互联网吗 深圳艾果互联网通讯科技 晋城互联网科技 四川慕妮娅互联网科技有限公司 沐思想互联网科技有限公司 元气玛特互联网科技公司是外包吗 锡山区互联网智能科技产品供应 江苏苏星互联网科技有限公司 梅州GM互联网络科技有限公司 中天科技中国工业互联网 广州互联网高科技取餐柜 互联网金融运营模式中的金融科技 平安好医生打造互联网科技医疗 科技创新与互联网经济 涨乐互联网科技 科技互联网政务服务 金融科技 互联网金融 南京欣网互联网科技 甘肃拓世互联网科技有限公司 深圳市运趣互联网科技有限公司 米聚互联网科技南京有限公司排面 悟空问答互联网科技 数字科技和互联网金融哪个好
0