Vue 的响应式原理

1. 数据劫持

① Vue 2 使用defineproperty()

在 Vue 2.x 中,Vue 使用 Object.defineProperty() 来拦截对象属性的getter和setter。每当一个 Vue 实例被创建时,它会遍历所有传入的数据对象的属性,并将它们转换为 getter 和 setter。

javascript 复制代码
// 简化版示例
function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    get: function reactiveGetter() {
      // 收集依赖
      return val;
    },
    set: function reactiveSetter(newVal) {
      if (newVal === val) return;
      val = newVal;
      // 触发更新
    }
  });
}

局限性:

  • 它不能检测到新增或删除属性。
  • 对于数组的操作无法直接拦截,因此 Vue 需要重写数组的部分方法来实现响应式。

② Vue 3 使用 Proxy

从 Vue 3 开始,Vue 引入了 ES6 的 Proxy 来替代 Object.defineProperty()Proxy 提供了更强大的功能,可以拦截更多的操作类型,如添加新属性、删除属性等,并且可以递归地处理嵌套对象,而不需要像 Object.defineProperty() 那样手动遍历每个属性。

javascript 复制代码
// 简化版示例
const handler = {
  get(target, key, receiver) {
    // 收集依赖
    return Reflect.get(target, key, receiver);
  },
  set(target, key, value, receiver) {
    const result = Reflect.set(target, key, value, receiver);
    // 触发更新
    return result;
  }
};
const proxy = new Proxy(data, handler);

2. 依赖收集

Vue 使用观察者模式来实现依赖收集。每当渲染组件时,Vue 会执行模板中表达式的 getter,从而触发依赖收集过程。在此过程中,Vue 会记录哪些 watcher 订阅了特定的数据属性的变化。

  • Watcher:每一个需要响应数据变化的地方(例如,计算属性、渲染函数)都有一个对应的 watcher。watcher 负责监听它所关心的数据属性的变化,并在变化发生时更新相关的视图部分。

  • Dep(依赖):每个响应式属性都有一个关联的 Dep 实例,用来管理所有订阅它的 watcher。当该属性发生变化时,Dep 会通知所有的 watcher 进行更新。

3. 视图更新机制

当用户交互或其他代码导致数据属性发生变化时,Vue 的响应式系统会调用该属性的 setter 方法。setter 不仅会设置新的值,还会通知所有订阅了该属性变化的 watcher。然后,这些 watcher 会重新评估并触发视图更新。

  • 异步队列 :为了提高性能,Vue 将所有的 DOM 更新操作批量放入一个异步队列中,在下一个事件循环 tick 时统一执行。这减少了不必要的重绘和回流,提升了应用的效率。

    javascript 复制代码
    queueWatcher(watcher) {
      // 如果 watcher 已经在队列中,则跳过
      if (!watcher.id) {
        watcher.id = nextId++;
        queue.push(watcher);
      }
      // 批量更新
      nextTick(flushSchedulerQueue);
    }

4. 计算属性与侦听器

除了直接绑定到数据属性外,Vue 还提供了计算属性(computed properties)和侦听器(watchers),允许开发者基于现有数据派生出新的状态或者执行副作用操作。

  • 计算属性:计算属性是缓存的,只有在其依赖的数据发生变化时才会重新计算。它们非常适合用于复杂逻辑的推导或格式化输出。

  • 侦听器:侦听器则可以用来执行更复杂的逻辑,比如异步操作或开销较大的任务。侦听器可以在数据变化时立即执行,也可以指定深度监听。

5. Vue 3 中的改进

Vue 3 在多个方面对响应式系统进行了优化:

  • 更好的性能 :通过使用 Proxy 和更加高效的依赖跟踪机制,Vue 3 显著提高了响应式的性能。

  • 更简单的 API:引入了 Composition API,使得逻辑复用更加简单直观,同时支持 TypeScript 更加友好。

  • 细粒度的响应式 :Vue 3 提供了 reactiveref 两种方式来创建响应式对象,其中 ref 适用于单一值的响应式封装,而 reactive 则用于对象或数组。

  • 内置工具函数 :如 toRefsisRef,帮助开发者更好地管理和操作响应式对象。

相关推荐
华玥作者16 小时前
[特殊字符] VitePress 对接 Algolia AI 问答(DocSearch + AI Search)完整实战(下)
前端·人工智能·ai
Mr Xu_16 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠16 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
sleeppingfrog16 小时前
zebra通过zpl语言实现中文打印(二)
javascript
lang2015092816 小时前
JSR-340 :高性能Web开发新标准
java·前端·servlet
好家伙VCC17 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
未来之窗软件服务18 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
baidu_2474386118 小时前
Android ViewModel定时任务
android·开发语言·javascript
嘿起屁儿整18 小时前
面试点(网络层面)
前端·网络
VT.馒头18 小时前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript