Vue.js---watch 的实现原理

发布于:2025-05-18 ⋅ 阅读:(24) ⋅ 点赞:(0)

4.7 watch 的实现原理

watch本质上就是使用了effect以及options.scheduler

定义watch函数:

  // watch函数:传入参数source以及回调函数
    function watch(source , cb) {
      effect(
        () => source.foo,
        {
          scheduler(){
            // 回调函数
            cb()
          }
        }
      )
    }

watch接收两个参数分别是source和cb

  • source 是一个对象,我们希望监听它的 foo 属性的变化。
  • cb 是一个回调函数,当 source.foo 发生变化时,这个回调函数会被执行。

watch的使用:

    // 使用watch函数
    watch(obj , () => {
      console.log('值发生改变')
    })
    // 修改响应数据的值,导致回调函数执行
        obj.foo++

值发生改变

**改为更加通用:**除了foo发生改变,其他的发生改变也可以

修改思路:使用函数对传入的对象循环读取,traverse函数:传入对象以及一个set集合(存储已经访问过的),判断类型,类型过关就进行遍历。

    // traverse:值以及读取放入的set
    function traverse(value , seen = new Set){
      // 如果要读取的数据是原始值,或者已经读取过了,那么什么都不做
      if(typeof value !== 'object' || value === null || seen.has(value)){
        return;
      }
      // 暂时仅考虑value是一个对象,遍历value
      for(const k in value){
        traverse(value[k] , seen);
      }
    }
      // watch函数:传入参数source以及回调函数
    function watch(source , cb) {
      effect(
        // traverse
        () => traverse(source),
        {
          scheduler(){
            // 回调函数
            cb()
          }
        }
      )
    }

壮大watch—getter函数:

修改思路:定义一个getter,如果source是函数类型直接使用getter函数,如果不是则递归调取

    // watch函数:传入参数source以及回调函数
    function watch(source , cb) {
      // 定义getter
      let getter 
      if(typeof source === 'function'){
        getter = source
      }else {
        getter = () => traverse(source)
      }
      effect(
        () => getter(),
        {
          scheduler(){
            // 回调函数
            cb()
          }
        }
      )
    }

重要功能—新旧值

修改思路:这时候要拿到effect的返回参数,返回参数就是oldval,最核心的改动就是添加了懒加载lazy创建了一个懒加载effect,需要的时候才会执行,在值发生改变时,更新新值和旧值

    // watch函数:传入参数source以及回调函数
    function watch(source , cb) {
      // 定义getter
      let getter 
      if(typeof source === 'function'){
        getter = source
      }else {
        getter = () => traverse(source)
      }
      // 定义新旧值
      let newVal , oldVal
      const effectFn = effect(
        () => getter(),
        {
          lazy: true,
          scheduler(){
            // 值发生改变会发生,此时就有新值了
            newVal = effectFn()
            // 回调函数,传入新旧值
            cb(oldVal , newVal)
            // 一定要记得更新旧值
            oldVal = newVal
          }
        }
      )
      // 调用effectFn就是旧值
      oldVal = effectFn();
    }

source以及回调函数
function watch(source , cb) {
effect(
// traverse
() => traverse(source),
{
scheduler(){
// 回调函数
cb()
}
}
)
}


**壮大watch---getter函数:**

修改思路:定义一个getter,如果source是函数类型直接使用getter函数,如果不是则递归调取

// watch函数:传入参数source以及回调函数
function watch(source , cb) {
  // 定义getter
  let getter 
  if(typeof source === 'function'){
    getter = source
  }else {
    getter = () => traverse(source)
  }
  effect(
    () => getter(),
    {
      scheduler(){
        // 回调函数
        cb()
      }
    }
  )
}

**重要功能---新旧值**

修改思路:这时候要拿到effect的返回参数,返回参数就是oldval,最核心的改动就是添加了懒加载lazy创建了一个懒加载effect,需要的时候才会执行,在值发生改变时,更新新值和旧值

// watch函数:传入参数source以及回调函数
function watch(source , cb) {
  // 定义getter
  let getter 
  if(typeof source === 'function'){
    getter = source
  }else {
    getter = () => traverse(source)
  }
  // 定义新旧值
  let newVal , oldVal
  const effectFn = effect(
    () => getter(),
    {
      lazy: true,
      scheduler(){
        // 值发生改变会发生,此时就有新值了
        newVal = effectFn()
        // 回调函数,传入新旧值
        cb(oldVal , newVal)
        // 一定要记得更新旧值
        oldVal = newVal
      }
    }
  )
  // 调用effectFn就是旧值
  oldVal = effectFn();
}


网站公告

今日签到

点亮在社区的每一天
去签到