返回

从零开始的手写 Vue.js 响应式系统 —— effect(三)

前端

在上一篇中,我们使用 effect 函数实现了 computed 的懒执行和缓存机制。在这篇文章中,我们将继续深入探索 effect 函数的强大功能,实现 watch 的立即执行以及支持两种形式的观测。

computedwatch

computedwatch 都是 Vue.js 中常用的响应式特性,它们允许我们在数据变化时执行特定的操作。computed 主要用于计算派生数据,而 watch 则更通用,可以监听任何数据的变化。

从实现原理上来看,computed 其实就是一种特殊的 watchcomputed 会在数据变化时自动触发重新计算,而 watch 则需要手动调用 effect 函数来触发。

effect 中的立即执行

默认情况下,effect 函数会在数据变化后立即执行。但是,我们可以通过设置 scheduler 选项来延迟 effect 的执行。

effect(() => {
  // 延迟执行的代码
}, { scheduler: () => setTimeout(() => {}, 0) });

在上面的代码中,effect 函数中的代码会在数据变化后延迟执行。scheduler 选项是一个回调函数,它指定了 effect 函数的执行时机。

两种形式的观测

Vue.js 中的响应式系统支持两种形式的观测:

  • 追踪依赖: 当一个函数被执行时,它会追踪它所依赖的数据。如果这些数据发生变化,则函数会被重新执行。
  • 手动触发: 可以通过调用 effect 函数来手动触发一个函数的执行。

实现 watch

我们可以利用 effect 函数的立即执行和手动触发的特性来实现 watch

function watch(source, callback) {
  let oldValue;
  effect(() => {
    const newValue = source();
    if (newValue !== oldValue) {
      callback(newValue, oldValue);
      oldValue = newValue;
    }
  }, { immediate: true });
}

在上面的代码中,我们使用 effect 函数来监听 source 的变化。当 source 发生变化时,effect 函数中的代码会被立即执行。如果新旧值不相等,则会调用 callback 函数,并更新 oldValue 的值。

示例

下面是一个使用 watch 函数的示例:

const count = ref(0);
watch(count, (newValue, oldValue) => {
  console.log(`Count changed from ${oldValue} to ${newValue}`);
});

在上面的示例中,我们使用 watch 函数来监听 count 的变化。当 count 发生变化时,控制台会打印出新旧值。

总结

通过利用 effect 函数的强大功能,我们可以实现 computedwatch 的响应式特性。computed 主要用于计算派生数据,而 watch 则更通用,可以监听任何数据的变化。通过理解这两种响应式特性的实现原理,我们可以更深入地了解 Vue.js 的响应式系统。