背景
前端面试100道手写题第二篇《throttle与debounce》,说一下为什么选这两个,其实大家都有在用,我们先来了解一下两个函数的作用:
- debounce 防抖,用于减少函数触发的频率,在一个delay时间内,如果触发delay时间归零,直到delay时间到才会触发函数
- throttle 节流,用于限制函数触发的频率,每个delay时间间隔,最多只能执行函数一次
选这两个手写的原因其实很简单,就是面试频率高,而且项目实战会经常用到,同时里面还会隐藏一些知识点和目前公共库的一些问题(见文章末尾)。
接下来就让我们开始手写撸代码吧!
手写难度:⭐️⭐️⭐️
不想看啰里吧嗦的文字,可以直接去看完整源码地址(记得给个star),地址如下:
https://github.com/qiubohong/hundred-interview-questions/tree/main/2-debouce-throttle
debounce
很多功能函数只要搞清楚他们的功能设计,基本上你就可以手写出完整的代码。
以lodash.debounce为参考,接下来我们来拆解一下完整的debounce的功能具体有哪些:
- 构造函数
debounce(func, waitTime, maxWait, leading, trailing)
- func (Function): 要防抖的函数。
- [wait=0] (number): 需要防抖的毫秒。
- [leading=false] (boolean): 指定调用在防抖开始前。
- [trailing=true] (boolean): 指定是否在最大等待时间过期后直接调用,简单点的当超过等待时间,则会触发函数
- [maxWait=wait] (number): 设置最大等待时间过期。
- 取消函数
debounceReturn.cancel()
,debounceReturn
是执行完debounce函数返回的对象 - 状态函数
debounceReturn.pending()
- 立即调用函数
debounceReturn.flush()
上面是lodash
给出debounce的完整功能,但是如果是我们仅仅需要简易版本的throttle,应该如何实现呢?
拆解步骤一:实现一个简单版
debounce()
函数最简单功能就是,希望能在wait时间段禁止重复触发某个事件,第一个简易版如下:
1 | function debounce_easy(func, waitTime){ |
拆解步骤二:leading参数希望可以先执行一次函数,再进行防抖, 具体代码如下:
1 | // 其实就是在定时器之前判断 leading和 timeout定期器是否不为空即可 关键代码如下 |
拆解步骤三:加上cancel等函数实现,这里能实现完基本上手写题就80分了
1 | /** |
拆解步骤四:加上参数 traling+maxWait
函数,作用在当超过maxWait等待时间后,函数会
重点在于判断是否过了等待时间,所以需要记录每次执行的时间,当超过的时候判断是否有传参数traling+maxWait
实现步骤如下流程所示:
参数解释:
- lastArgs, // 上一次调用时的参数
- lastThis, // 上一次调用时的this
- result, // 上一次调用的返回值
- lastCallTime, // 上一次调用的时间
- lastInvokeTime = 0, // 上一次执行的时间
- leading = false, // 是否立即执行
- maxing = false, // 是否有最大等待时间
- trailing = true; // 是否在最后一次调用后执行
throttle
throttle
节流函数定义:就是无论频率多快,每过一段时间就执行一次。
在实现逻辑上其实是可以看做debounce
的一种升级版,只需要保证debounce函数在超时后执行一次函数即可
只要针对debouonce函数设置一下参数即可,代码如下:
1 | function throttle(func, wait, leading = true){ |
当然我们也可以实现一个快速简单版,代码如下:
1 | function throttle_eazy(func, wait) { |
额外知识点
TDD开发模式
一般写这些工具函数,都需要提前想好单元测试怎么写,这就是涉及一种开发模式测试驱动开发(TDD),主要遵循以下两个原则:
- 仅在自动测试失败时才编写新代码。
- 消除重复设计(去除不必要的依赖关系),优化设计结构(逐渐使代码一般化)。
TDD的研发流程如下:
lodash的缺陷
如果你正在使用lodash,你应该关注一下,因为lodash的github最后一次更新2021年4月24号,到目前为止已经有两年的时间没有更新,已经堆积很多issues,从上面解读源码的时候就发现一个lodash.throttle
的一个bug,如下:
1 | const changeInput = throttle((value: string)=>{ |
同时,lodash还有其他一些缺陷:
- lodash是支持tree shaking,但是这么写
import {throttle} from 'lodash'
会将整个lodash包都引入, 必须这么写import throttle from 'lodash/throttle'
才能做到按需加载 - 进入 npm 上的 lodash 包,它被列为 v4.17.21,并且已经 2 年多没有发布了:https://www.npmjs.com/package/lodash
当然作为一个工具库lodash确实可以让我们少写很多代码,但是已经很长时间没有维护的问题还是需要关注的。
参考资料
- 本文作者: Qborfy
- 本文链接: https://www.qborfy.com/face100/2-throttle-debouce.html
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!