Skip to content

30.computed 和 watch 区别

Vue2 中有三种 watcher (渲染 watcher 、计算属性 watcher、 用户 watcher)
Vue3 中有三种 effect (渲染 effect 、计算属性 effect、 用户 effect)

1.1 computed

  • 计算属性仅当用户取值时才会执行对应的方法。
  • computed 属性是具备缓存的,依赖的值不发生变化,对其取值时计算属性方法不会重新执行。
  • 计算属性可以简化模板中复杂表达式。
  • 计算属性中不支持异步逻辑。
  • computed 属性是可以再模板中使用的。

1.2 watch

watch 则是监控值的变化,当值发生变化时调用对应的回调函数。经常用于监控某个值的变化,进行一些操作。(异步要注意竞态问题。)

vue
<template>
  <div>
    <input v-model="value" />
    {{ result }}
  </div>
</template>
<script>
export default {
  name: "App",
  components: {},
  data() {
    return {
      result: "",
      timer: 3000,
    };
  },
  methods: {
    async getData(newVal) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(newVal);
        }, (this.timer -= 1000));
      });
    },
  },
  mounted() {
    let arr = [];
    this.$watch("value", async (newVal, oldValue) => {
      let clear = false;
      while (arr.length > 0) {
        arr.shift()();
      }
      arr.push(() => {
        clear = true; // 利用闭包实现清理操作
      });
      let result = await this.getData(newVal);
      if (!clear) this.result = result;
    });
  },
};
</script>
<template>
  <div>
    <input v-model="value" />
    {{ result }}
  </div>
</template>
<script>
export default {
  name: "App",
  components: {},
  data() {
    return {
      result: "",
      timer: 3000,
    };
  },
  methods: {
    async getData(newVal) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(newVal);
        }, (this.timer -= 1000));
      });
    },
  },
  mounted() {
    let arr = [];
    this.$watch("value", async (newVal, oldValue) => {
      let clear = false;
      while (arr.length > 0) {
        arr.shift()();
      }
      arr.push(() => {
        clear = true; // 利用闭包实现清理操作
      });
      let result = await this.getData(newVal);
      if (!clear) this.result = result;
    });
  },
};
</script>

vue3 提供了 onCleanup 函数,让用户更加方便使用也解决了清理问题。

js
watch(
    () => this.value,
    async (newVal, oldValue, onCleanup) => {
    let clear = false;
    onCleanup(() => {
        clear = true;
    });
    let result = await this.getData(newVal);
    if (!clear) this.result = result as string;
    }
);
watch(
    () => this.value,
    async (newVal, oldValue, onCleanup) => {
    let clear = false;
    onCleanup(() => {
        clear = true;
    });
    let result = await this.getData(newVal);
    if (!clear) this.result = result as string;
    }
);

1.3 源码剖析

Vue2 源码Vue3 源码

Released under the MIT License.