本文使用“署名-非商业性使用-相同方式共享 4.0 国际(CC BY-NC-SA 4.0)”进行许可。
商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接。 如果您再混合、转换或者基于本作品进行创作,您必须基于相同的协议分发您贡献的作品。
lodash 和其他很多工具库(比如 VueUse)都有 debounce(防抖)和 throttle(节流)的概念。简单(且有点不严谨)地讲,如果事件一直被触发,debounce 之后在最后停下来之后处理它,而 throttle 会每隔一段固定时间去处理它。
Note
在本文中我“刻意地”没有加入任何一行代码,因为发现在阅读别人的相关文章学习时,他们给出的大段代码并没有很好帮助我理解,反而是一些概念原本可以用自然语言说清楚,却非要让读者读代码来理解,造成了一个很大的 friction。如果你是那种喜欢看代码来理解的人,可以直接看 lodash 的 Debounce 源码 和 Throttle 源码, 或者在 #参考阅读 中找篇文章看。
防抖和节流确实是非常常见和基础的东西,有能搜到的相关文章多如牛毛,我也一直在犹豫要不要吧本文发出来。最后发现本文和其他文章还是有“无代码”这个差异点,于是选择了发布。
先从 Debounce 说起吧。一般我们把 Debounce 翻译为防抖,通常用于处理用户的文本输入。
Debounce 一个比较正式的定义来自 lodash 的文档:
Creates a debounced function that delays invoking
func
until afterwait
milliseconds have elapsed since the last time the debounced function was invoked.
这里涉及到了两个函数,第一个是原本的、需要被防抖的函数 F
,第二个是 _.debounce
函数返回的、防抖过的函数 F'
。这段定义就是只有在最后一次 F'
被调用若干时间后才会调用 F
。如果在等待这“若干时间”里 F'
又被调用了,那么这次的调用就变成了“最后一次”,所以需要重新等待。
上面的解释还是有点抽象,用很简单的说法来说,就是如果不停的调用 F'
,那么真正的函数 F
不会被调用,直到对 F'
的调用停下来若干时间之后。用常见的输入框防抖来说,如果 wait
被设置成了 300 ms,那么如果用户一直以 200 ms 的间隔输入字符,那么函数一直不会被调用,直到用户停止输入(300ms)之后,F 才会被调用。
这时候看 lodash debounce 的参数, wait
的含义应该不用多说;剩下还有 maxWait
和 leading
& trailing
。这篇文章里我不打算深入研究 leading
和 trailing
,感兴趣的可以看 这篇文章,至于 maxWait
,则是如果一直在等待的话,最多等 maxWait
毫秒就要调用一次。还是拿上面的输入框例子来说。如果设置了 maxWait
为 1000 ms,那么假如用户一直不停地输入了整整 5 秒钟,那么函数会在 1、2、3、4、5 秒后分别调用一次,因为它“最多只能等”1000ms;而如果没有 maxWait,则只会在 5s + 300ms 后调用 1 次。
Throttle 有些人翻译成“节流阀”,但是我觉得这里应该是用动词“节流/减速” 更好,和“防抖”相对。一般来说用来处理 Resize 或者 scroll 事件。
如果你理解了 Debounce 和它的 maxWait
参数,理解 Throttle 应该是易如反掌的。先看 lodash 的定义:
Creates a throttled function that only invokes
func
at most once per everywait
milliseconds.
也就是说,如果一直调用,那么真正的函数每 wait
ms 触发一次。
有没有感觉和 debounce 的 maxWait
有点像?实际上,_.throttle
就只是 _.debounce
的一个简单包装,将 debounce 的 maxWait
设置得和 wait
一样,就得到了一个 Throttle 函数!如果感兴趣,可以看 这不到20行代码的实现
和 Debounce 一样,如果你对 leading
和 trailing
参数感兴趣,可以查看 这篇文章
Debounce vs Throttle: Definitive Visual Guide
Throttle & Debounce behavior (lodash)
Debouncing And Throttling Explained Through Examples | CSS-Tricks
本文使用“署名-非商业性使用-相同方式共享 4.0 国际(CC BY-NC-SA 4.0)”进行许可。
商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接。 如果您再混合、转换或者基于本作品进行创作,您必须基于相同的协议分发您贡献的作品。