「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战」。
前言
大家好,我是轮子猫。本系列文章将带你使用TDD的方式每天花费5分钟,完成一个大厂笔试、面试必考手写题目。
- 防抖
- 节流
- call、apply、bind
- EventEmitter
- 手动实现ES5继承
- 手动实现instanceof
- Object.create
- new
- 浅拷贝和深拷贝
- 单例模式
- 手动实现JSONP
- 数组去重、扁平、最值
- 数组乱序 - 洗牌算法
- 函数柯里化
- 模拟实现promise
- 基于Promise的ajax封装
- 异步循环打印
- 图片懒加载
需求
在实现防抖之前,我们先来了解一下防抖的定义。防抖指的是,不管事件触发频率有多高,一定事件触发n秒后才执行。如果你在一个事件触发的n秒内又触发了这个事件,就以新的事件的时间为准,n秒后才执行并取消前面触发的事件。
现在我们来拆解一下需求:
- 函数触发n秒后才执行,也就是延迟执行函数
- 函数在n秒被连续触发,前面被触发等待的函数,都取消执行。并且重新以这次的触发事件时间为准,延迟执行该函数。
实现
现在我们来一步一步实现防抖。
需求1
首先,我们先实现关于延迟执行函数的测试代码
// debounce.test.js
test('should dealy function', function(done) {
const mockFn = jest.fn();
const debouncedFn = debounce(mockFn, 10);
debouncedFn();
expect(mockFn.toBeCalledTimes(0);
setTimeout(function() {
expect(mockFn).toBeCalledTimes(1);
done();
}, 20);
})
运行测试代码
实现测试代码
// debounce.js
function debounce(fn, n) {
return function () {
setTimeout(function () {
fn();
}, n);
};
}
接着,我们继续运行测试代码,OK
需求2
现在,我们来实现拆解后的需求2,测试代码如下
// debounce.test.js
test('should debounce function', function() {
const mockFn = jest.fn()
const debouncedFn = debounce(mockFn, 10);
debouncedFn()
debouncedFn()
expect(mockFn).toBeCalledTimes(0);
setTimeout(function () {
expect(mockFn).toBeCalledTimes(1);
done();
}, 20);
})
实现
// debounce.js
function debounce(fn, n) {
let prev = 0
let id
return function (...args) {
// 1. 如果函数调用的时间在n秒内:这次函数开始调用的时间 - 上一次函数开始设置定时器的时间
const now = Datw.now()
if (id && now - prev <= n) {
// 2. 取消刚刚的函数调用
clearTimeout(id)
}
// 3. 以新的调用事件为准,n秒后才执行
prev = Date.now()
id = setTimeout(function () {
fn(...args);
}, n);
};
}
最后,运行测试代码
这样,最基本的防抖函数就已经成功实现了,收工!~