防抖与节流
基本概念
- 防抖(debounce): n 秒后在执行该回调,若在 n 秒内被重复触发,则重新计时。场景:不可控的高频触发,如点击按钮、输入框搜索
- 节流(throttle): n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效。场景:快速连续的触发,如滚动条事件、mousemove
假设电梯有两种运行策略
防抖
和节流
,超时设定为15秒,不考虑容量限制 电梯第一个人进来后,15秒后准时运送一次,这是节流。 电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖。
两者的区别:
- 防抖可能用于无法预知的用户主动行为,如用户输入内容去服务端动态搜索结果。用户打字的速度等是无法预知的,具有非规律性。
- 节流可能用于一些非用户主动行为或者可预知的用户主动行为,如用户滑动商品橱窗时发送埋点请求、滑动固定的高度是已知的逻辑,具有规律性。
- 防抖是关注于最后一次的事件触发,而节流则是在规定的时间里只执行一次。
防抖代码实现
// 防抖-非立即执行
function laterDebounce(fn, wait) {
var timer = null
return function () {
var context = this
var args = arguments
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(context, args)
}, wait)
}
}
// 防抖-立即执行,立即执行的意思是先执行再等待,会出现wait时间内连续点击两次,第二次无效的情况
function immediateDebounce(fn, wait) {
var timer = null
var flag = true
return function () {
var context = this
var args = arguments
clearTimeout(timer)
if (flag) {
fn.apply(context, args)
flag = false
}
timer = setTimeout(() => {
flag = true
}, wait)
}
}
// 第一次点击立即执行,接下来防抖(比较符合场景)
function firstImmediateDebounce(fn, wait, immediate) {
var timer = null
var count = 0
return function () {
var context = this
var args = arguments
clearTimeout(timer)
if (immediate && count === 0) {
fn.apply(context, args)
count++
} else {
timer = setTimeout(() => {
fn.apply(context, args)
count++
}, wait)
}
}
}
节流代码实现
// 节流:时间戳写法
function throttle1(fn, wait) {
var oldTime = 0
return function () {
var now = Date.now()
if (now - oldTime >= wait) {
var context = this
var args = arguments
fn.apply(context, args)
oldTime = Date.now()
}
}
}
// 节流:定时器写法
function throttle2(fn, wait) {
var canExec = true
var timer = null
return function () {
if (canExec) {
canExec = false
var context = this
var args = arguments
fn.apply(context, args)
timer = setTimeout(() => {
canExec = true
clearTimeout(timer)
}, wait)
}
}
}