跟着underscore学防抖

44 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。

【若川视野 x 源码共读】第25期 | 跟着underscore学防抖 点击了解本期详情一起参与

防抖 (debounce)

防抖,顾名思义,防止抖动,以免把一次事件误认为多次,敲键盘就是一个每天都会接触到的防抖操作。

  1. 学会防抖的使用场景
  2. 学会防抖的原理和实现
  3. 学会使用测试用例测试源码

使用场景

学习一个功能要先知道它的使用场景:

  1. 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖
  2. 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖
  3. 文本编辑器实时保存,当无任何更改操作一秒后进行保存

对应的事件有以下:

  1. window 的 resize、scroll
  2. mousedown、mousemove
  3. keyup、keydown
  4. click 。。。等

防抖的原理和实现

防抖的核心原则是,在一定是时间内,多次触发同一个事件时,只执行最后一次触发事件的函数的调用,而忽略之前的触发事件。 代码实现则是用在使用定时器setTimeout,清零 clearTimeout,以及闭包来实现的

// debounce.js
export function debounce(func, delay) {
  let timer
  // timer形成闭包
  return function (...args) {
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      func(...args)
    }, delay)
  }
}

学会使用测试用例测试源码

// debounce.test.js
import { describe, it, beforeEach, vi, afterEach, expect } from 'vitest'
import { debounce } from './debounce'

describe('test debounce', () => {
  beforeEach(() => {
    console.log('beforeEach')
    // 要启用模拟计时器,你需要调用此方法。
    vi.useFakeTimers()
  })
  afterEach(() => {
    console.log('beforeEach')
    // 重置时间
    vi.useRealTimers()
  })
  it('3秒内只执行一次', () => {
    const mock = vi.fn(() => console.log(`debounce`))
    const debounced = debounce(mock, 1000 * 3)
    debounced()
    setTimeout(()=>{
      debounced()
    }, 5000)
    vi.runAllTimers()
    expect(mock).toHaveBeenCalledTimes(2)
  })
})

image.png

总结:

本文学习到了

  1. 防抖的使用场景
  2. 防抖的原理
  3. 使用测试用例来测试源码

使用vitest编写测试用例时的意外收获: npx 命令将从本地 node_modules/.bin 执行命令,安装命令运行所需的任何包。 默认情况下,npx 将检查命令是否存在于 $PATH 或本地项目二进制文件中,并执行它。 如果未找到命令,它将在执行之前安装。