本文已参与「新人创作礼」活动,一起开启掘金创作之路。
本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
【若川视野 x 源码共读】第25期 | 跟着underscore学防抖 点击了解本期详情一起参与。
本文涉及
需要防抖的场景
防抖的定义
实现一个简单的防抖
源码分析功能点
使用场景
节流和防抖本质上是用来优化高频率执行事件的一种手段
高频的执行事件,如浏览器的 resize
、scroll
、keypress
、mousemove
等事件,当这些事件触发时,会不停的调用回调函数
我们以地铁为例,
-
节流就是只要人一上车,开始倒计时,时间一到就走
-
防抖就是有人上车,开始倒计时,在计时过程中如果还有人上车,则重新开始计时,直到
没有人上车 && 计时器到点
我们尝试着自己实现一个debounce
函数
// debounce.js
export function debounce(func, wait) {
let timeout, result
return function (...args) {
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(() => {
result = func.apply(this, args)
}, wait)
return result
}
}
测试用例
// debounce.test.js
import { describe, it, beforeEach, vi, afterEach, expect } from 'vitest'
import { debounce } from './debounce'
describe('test debounce', () => {
beforeEach(() => {
// 使用 mock 时间
vi.useFakeTimers()
})
afterEach(() => {
// 重置时间
vi.useRealTimers()
})
it('5秒内只执行一次', () => {
const mock = vi.fn(() => console.log(`Hello JueJin`))
const debounced = debounce(mock, 1000 * 5)
debounced()
debounced()
vi.runAllTimers()
expect(mock).toHaveBeenCalledTimes(1)
})
})
源码分析
我们来看下源码是怎么实现的
import restArguments from './restArguments.js'
import now from './now.js'
export default function debounce(func, wait, immediate) {
var timeout, previous, args, result, context
var later = function () {
// 是否超时
// 没有超时:重置计时器并设定此时的时间为 wait - passed
// 超时:清空计时器,执行func
var passed = now() - previous
if (wait > passed) {
timeout = setTimeout(later, wait - passed)
} else {
timeout = null
if (!immediate) result = func.apply(context, args)
// 避免func中再次调用debounced
if (!timeout) args = context = null
}
}
var debounced = restArguments(function (_args) {
context = this
args = _args
previous = now()
if (!timeout) {
timeout = setTimeout(later, wait)
// 立即执行func
if (immediate) result = func.apply(context, args)
}
return result
})
// 手动取消
debounced.cancel = function () {
clearTimeout(timeout)
timeout = args = context = null
}
return debounced
}
源码上考虑到了几点:
- 事件可以立即执行
func
中再次调用debounce
的问题- 可以手动取消
总结
源码考虑到的使用场景更多,涉及到的功能点也更加完善。
-
需要防抖的场景
- 优化高频率执行事件的一种手段
-
防抖的定义
- 在事件触发后,在一定时间后执行回调函数,如果在一定时间内再次触发,则重新计算时间
-
实现一个简单的防抖
-
源码分析功能点