本文已参与「新人创作礼」活动,一起开启掘金创作之路。
本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
【若川视野 x 源码共读】第25期 | 跟着underscore学防抖 点击了解本期详情一起参与。
防抖 (debounce)
防抖,顾名思义,防止抖动,以免把一次事件误认为多次,敲键盘就是一个每天都会接触到的防抖操作。
- 学会防抖的使用场景
- 学会防抖的原理和实现
- 学会使用测试用例测试源码
使用场景
学习一个功能要先知道它的使用场景:
- 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖
- 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖
- 文本编辑器实时保存,当无任何更改操作一秒后进行保存
对应的事件有以下:
- window 的 resize、scroll
- mousedown、mousemove
- keyup、keydown
- 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)
})
})
总结:
本文学习到了
- 防抖的使用场景
- 防抖的原理
- 使用测试用例来测试源码
使用vitest编写测试用例时的意外收获:
npx
命令将从本地 node_modules/.bin
执行命令,安装命令运行所需的任何包。 默认情况下,npx 将检查命令是否存在于 $PATH 或本地项目二进制文件中,并执行它。 如果未找到命令,它将在执行之前安装。