出处:掘金
原作者:金泽宸
它们是前端性能优化的“老三样”之一,常用于:
| 特性 | 防抖(debounce) | 节流(throttle) |
|---|---|---|
| 执行时机 | 停止一段时间后执行一次 | 固定时间间隔内最多执行一次 |
| 场景 | 搜索框输入、按钮防重复提交 | 页面滚动、resize、mousemove |
![[函数防抖与节流.png]]
在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新计时
/**
* @description: 函数防抖:在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新计时。
* @param {function} func 需要防抖的函数
* @param {number=500} delay 延迟时间(单位为毫秒),默认 500
* @return {function}
*/
function debounce(func, delay = 500) {
let timer = null
return function(...args) {
timer && clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
timer = null
}, delay)
}
}
使用示例:
window.addEventListener('resize', debounce(() => {
console.log('窗口变化');
}, 500));
规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效
/**
* @description: 函数节流:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
* @param {function} func 需要节流的函数
* @param {number=500} wait 等待时间(单位为毫秒),默认 500
* @return {function}
*/
function throttle(func, wait = 500) {
let last = 0
return function(...args) {
const now = Date.now()
if (now - last < wait) return
last = now
func.apply(this, args)
}
}
/**
* @description: 函数节流:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
* @param {function} func 需要节流的函数
* @param {number=500} wait 等待时间(单位为毫秒),默认 500
* @return {function}
*/
function throttle(func, wait = 500) {
let timer = null
return function(...args) {
if (timer) return
timer = setTimeout(() => {
func.apply(this, args)
timer = null
}, wait)
}
}
/**
* @description: 函数节流:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
* @param {function} func 需要节流的函数
* @param {number=500} wait 等待时间(单位为毫秒),默认 500
* @return {function}
*/
function throttle(func, wait = 500) {
let timer = null
let start = 0
return function(...args) {
let now = Date.now()
let remainning = wait - (now - start) // 剩余时间
timer && clearTimeout(timer)
if (remainning <= 0) { // 没有剩余时间,需要立即执行
func.apply(this, args)
start = Date.now()
} else { // 有剩余时间,剩余时间结束后执行
timer = setTimeout(() => {
func.apply(this, args)
timer = null
}, remainning)
}
}
}
input、resize 等连续的事件,只需触发一次回调:
resize。只需窗口调整完成后,计算窗口大小。防止重复渲染scroll 等间隔一段时间执行一次回调:
| 问题 | 答案 |
|---|---|
| 防抖能否立即执行? | 可以,加 immediate 参数 |
| 节流 trailing 和 leading 如何实现? | 控制时间戳/定时器配合 |
| 节流和防抖能否合并? | 理论上不建议,但可以写工具库支持模式切换 |
this 和 arguments 会丢失吗? |
是的,需用 apply(this, args) 绑定上下文 |
lodash.debounce 和 lodash.throttle 内部实现有何异同?