Vue2-computed洋葱模型

114 阅读2分钟

洋葱模型是Vue框架中的一种数据依赖关系管理机制,用于实现响应式数据的更新和视图的重新渲染。 在Vue实例初始化时,每个计算属性都会关联一个懒加载的 Watcher,在访问计算属性时才会执行计算方法。

  • 使用 Watcherevaluate() 方法时,会让计算属性直接依赖的属性收集当前计算属性 Watcher,并建立起它们之间的依赖关系。
  • 使用 Watcherdepend() 方法时,则会将当前计算属性 Watcher 与其订阅的所有 dep 建立关联,使这些 dep 都能够收集上层 Watcher。以此确保在依赖数据发生变化或上层 Watcher 发生变化时,能够触发当前计算属性 Watcher 的更新,从而保证计算属性的响应式更新。

这种机制好比一个洋葱,数据依赖就像层层剥开的皮,底层数据变化会逐层传递触发更新,最终实现视图的同步渲染,保证数据响应式和视图更新的一致性。

1# computed 嵌套调用

以下示例实现了一个 Vue 组件嵌套调用计算属性的案例,其中:

  • 计算属性 point 返回一个字符串 [x, y],包含 xy 的值。

  • 计算属性 combined 返回一个对象,包含 startend 的值与计算属性 point

<template>
  <p>嵌套的计算属性:{{ combined }}</p>
</template>

<script>
export default {
  data() {
    return {
      start: 0, // 起点
      end: 10, // 终点
      x: 0, // x 坐标
      y: 5, // y 坐标
    };
  },
  computed: {
    combined: function () {
      return {
        start: this.start,
        end: this.end,
        point: this.point,
      };
    },
    point: function() {
      return `[${this.x}, ${this.y}]`;
    }
  },
};
</script>

2# Watcher 调用步骤

Step 1. 初始化组件时,render-watcher 入栈

  • stack: [render-watcher]

Step 2. 当 render 函数访问 combined 计算属性时,执行 combined-watcherevaluate() 方法并入栈。

  • stack: [render-watcher, combined-watcher]
    • render-watcher: [combined]

Step 3. 当执行 combined-watcherget() 方法时,其直接依赖的 startend 会去收集当前的 combined-watcher;之后又访问 point 计算属性,执行 point-watcherevaluate() 方法并入栈。

  • stack: [render-watcher, combined-watcher, point-watcher]
    • render-watcher: [combined]
    • combined-watcher:[start, end, point]

Step 4. 当执行 point-watcherget() 方法时,其直接依赖的 xy 会去收集当前的 point-watcher

  • stack: [render-watcher, combined-watcher, point-watcher]
    • render-watcher: [combined]
    • combined-watcher:[start, end, point]
    • point-watcher:[x, y]

Step 5. point-watcher 出栈并执行 depend() 方法,让 point-watcher 订阅的 dep 再去收集当前 combined-watcher 依赖。

  • stack: [render-watcher, combined-watcher]
    • render-watcher: [combined]
    • combined-watcher:[start, end, x, y]

Step 6. combined-watcher 出栈并执行 depend() 方法,让 combined-watcher 订阅的 dep 再去收集当前 render-watcher 依赖,至此完成了视图更新的全过程。

  • stack: [render-watcher]
    • render-watcher: [start, end, x, y]

3# 示意图

vue2-computed-1.tif

vue2-computed-2.tif