手写 —— 防抖和节流

防抖和节流都是为了解决短时间内大量触发某函数而导致的性能问题,比如触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象

防抖(debounce)

在事件被触发 n 秒后再执行回调函数,如果在这 n 秒内又被触发,则重新计时(短时间内连续触发的事件 只有效执行一次)

应用场景

  • 用户在输入框中连续输入一串字符后,只会在输入完后去执行最后一次的查询请求,这样可以有效减少请求次数,节约请求资源

  • window 的 resize、scroll 事件,不断地调整浏览器的窗口大小、或者滚动时会触发对应事件,防抖让其只触发一次

节流(throttle)

规定一个单位时间 n,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内事件被触发多次,只有一次能生效(每 n 秒触发一次)

应用场景

  • 鼠标连续不断地触发某事件(如点击),n 秒内只触发一次

  • 监听滚动事件,比如是否滑到底部自动加载更多

区别

防抖的作用是将多个连续的debounced调用合并为一次callback调用。防抖是基于最近次 debounced 调用来重置 waitTime,如果debounced事件触发间隔小于 waitTimecallback就不会执行;

节流的作用是限制callback调用的频率(每waitTime调用一次)。是基于上次 callback 调用来计算 waitTime 的,不管callback 事件触发有多频繁,只要距离上次 callback 调用超过了 waitTime,就一定会进行下次 callback 调用。

– 原理:

防抖是 debounced 维护了一个计时器,规定在 waitTime 时间后触发 callback,但是在 waitTime 时间内再次触发 debounced 的话,会清除当前的 timer 然后重新计时,这样一来,只有最后一次debounced 操作才能触发 callback

节流是通过判断是否到达一定时间 (waitTime) 来再次触发 callbackfuncwaitTime 时间内不能被再次触发。

实现

throttle-debounce 插件

简单实现

// 节流
function throttle(delay, func) {
let flag = true
return function() {
const context = this
const arg = arguments
if (flag) {
flag = false
setTimeout(() => {
flag = true
func.apply(context, arg)
}, delay)
}
}
}

// 防抖
function debounce(delay, func) {
let timer = null
return function() {
const context = this
const args = arguments

clearTimeout(timer)
timer = setTimeout(function() {
func.apply(context, args)
}, delay)
}
}