详解Lodash中的debounce和throttle

在前端开发中,有两个常用的高阶函数:debounce 与 throttle。它们经常用来防止函数被高频调用。
本文详细说明了 Lodash 中 debounce 和 throttle 的使用方法。

debounce(去抖)

bounce可以翻译为弹跳、跳跃。

我们可以对应几个场景来进一步理解 bounce:

  • 有一根弹簧,一端固定好,另一端拉伸后松开,弹簧就会在一定时间内不停地 bounce。
  • 在街舞的教学中,有的老师会和学生强调 “bounce” 的练习。可以粗略的理解为:身体跟着音乐要不停地律动。
  • 在我们使用鼠标时,有时候会连续点击鼠标。

概括来说,bounce 可以广义理解为:在一定时间内连续做某件事。

了解了bounce,debounce 要做什么事情就变得非常清晰:阻止在一定时间内连续做某件事。

Lodash 中的 debounce 方法使我们可以将连续多次的函数调用归为一次调用。

函数原型及参数详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 创建一个会在 `wait` 毫秒后调用 `func` 的防抖动函数。
* 最后一次传入 `func` 参数会传给防抖动函数,随后调用的防抖动函数返回是最后一次 func 调用的结果。
* 防抖动函数提供 cancel 方法来取消延迟的函数调用 以及 flush 方法来立即执行函数调用。
*
* 注意: 如果 leading 和 trailing 都设定为 true,则 func 允许 trailing 方式调用的条件为: 在 wait 期间多次调用。
*
* @param {Function} func 要防抖动的函数
* @param {number} [wait=0] 需要延迟的毫秒数
* @param {Object} [options={}] 选项对象
* @param {boolean} [options.leading=false] 指定调用在延迟开始前
* @param {number} [options.maxWait] 设置 `func` 允许被延迟的最大值
* @param {boolean} [options.trailing=true] 指定调用在延迟结束后
* @returns {Function} 返回一个具有防抖动功能的函数
*/

_.debounce(func, [wait=0], [options])

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 避免窗口在变动时出现昂贵的计算开销
jQuery(window).on('resize', debounce(calculateLayout, 150))

// 当点击时 `sendMail` 随后就被调用
jQuery(element).on('click', debounce(sendMail, 300, {
'leading': true,
'trailing': false
}))

// 确保 `batchLog` 调用1次之后,1秒内会被触发
const debounced = debounce(batchLog, 250, { 'maxWait': 1000 })
const source = new EventSource('/stream')
jQuery(source).on('message', debounced)

// 取消一个 trailing 的防抖动调用
jQuery(window).on('popstate', debounced.cancel)

throttle(节流阀)

从字面意思上看可以理解为事件在一个管道中传输,加上这个节流阀以后,事件的流速就会减慢。

throttle 的实际作用也是如此:限制一个函数在一定时间内只能执行一次。

函数原型及参数详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 创建一个在 wait 秒内最多执行 func 一次的节流函数。
* 最后一次传入 `func` 参数会传给节流函数,随后调用的节流函数返回是最后一次 func 调用的结果。
* 节流函数提供 cancel 方法来取消延迟的函数调用 以及 flush 方法来立即执行函数调用。
*
* 注意: 如果 leading 和 trailing 都设定为 true,则 func 允许 trailing 方式调用的条件为: 在 wait 期间多次调用。
*
* @param {Function} func 要节流的函数
* @param {number} [wait=0] 需要节流的毫秒
* @param {Object} [options={}] 选项对象
* @param {boolean} [options.leading=true] 指定调用在节流开始前
* @param {boolean} [options.trailing=true] 指定调用在节流结束后
* @returns {Function} 返回一个具有防抖动功能的函数
*/

_.throttle(func, [wait=0], [options])

示例

1
2
3
4
5
6
7
8
9
// 避免在滚动时过分的更新定位
jQuery(window).on('scroll', throttle(updatePosition, 100))

// 点击后就调用 `renewToken`,但5分钟内超过1次。
const throttled = throttle(renewToken, 300000, { 'trailing': false })
jQuery(element).on('click', throttled);

// 取消一个 trailing 的节流调用
jQuery(window).on('popstate', throttled.cancel)

debounce 和 throttle 区别

在 Lodash 中,throttle 方法是基于 debounce 实现的。

主要区别是 throttle 保证方法每 wait 秒内有规律的执行。

一个相当常见的例子,用户在你无限滚动的页面上向下拖动,你需要判断现在距离页面底部多少。
如果用户快接近底部时,我们应该发送请求来加载更多内容到页面。
这种情况下, debounce 是没有用的,因为它只会在用户停止滚动时触发,但我们需要用户快到达底部时去请求。
通过 throttle 我们可以不间断的监测距离底部多远。


参考

志遥 wechat
微信扫一扫,关注丁香园记公众号,第一时间收到志遥的所思所想。