vue3官网防抖ref?

作者站长头像
站长
· 阅读数 5

以下是vue3官网的代码 “防抖ref”

import { customRef } from 'vue'

export function useDebouncedRef(value, delay = 200) {
  let timeout
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          value = newValue
          trigger()
        }, delay)
      }
    }
  })
}

为什么set的时候,定时器已经清除了,定时器里的内容还会执行呢?newValue的值还会一直在,并且累积到200ms后全部执行

回复
1个回答
avatar
test
2024-07-09

因为清除的是上一次调用set时生成的延时器。clearTimeout并不介意接收一个已经执行过的延时器,所以clearTimeout(timeout)的实际效果等价于:

if(xxxxx){
  // 如果 timeout 对应的延时器有效,就清除该延时器
  clearTimeout(timeout)
} else {
  // 如果该延时器无效,就不用管
}
// 以上,timeout 指的是“上一次”的延时器
// 后面可以重新给 timeout 赋值,此后 timeout 就成了“这一次”的延时器
// 上面清除的是“上一次”的延时器,不会影响“这一次”的回调函数

那你可能会说,“下一次”执行set的时候岂不是就把“这一次”设置的timeout给清除掉了?这就要看“下一次”是什么时候执行的:

  • 如果这个时候timeout还没有过期,那么确实就应该把它给清除掉,这就是“防抖”的含义——时间小于某个阈值的连续操作,需要取消前面一次操作;

    注意这里不存在“积累到200ms之后全部执行”的说法,而是上一次的newValue在清除的时候就直接取消了,面试的时候可不能那样理解。
  • 如果这个时候timeout已经过期了,那么清除不影响已经执行过的“上一次”的代码。
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容