防抖和节流,本质上是优化高频率执行代码的一种手段,比如:resize、scroll、keypress、mousemove这些事件在触发的时候,会不断调用绑定在事件上的回调函数,这样极大浪费资源,降低前端性能。
为了优化体验,需要对这类事件进行调用次数的限制,所以我们采取了防抖和节流的手段来减少调用频率。
节流:在n秒内重复发生的事件,只有一次是生效的
防抖:在n秒后再执行该事件。
节流
完成节流可以使用时间戳与定时器的写法,使用时间戳的写法,事件会立即执行,停止触发后没有办法再次执行:
javascript
function throttled1(fn, delay = 500) {
let oldtime = Date.now()
return function (...args) {
let newtime = Date.now()
if (newtime - oldtime >= delay) {
fn.apply(null, args)
oldtime = Date.now()
}
}
}
使用定时器的写法,delay毫秒后第一次执行:
javascript
function throttled2(fn, delay = 500) {
let timer = null
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay);
}
}
}
两种写法的结合后:
javascript
function throttled(fn, delay) {
let timer = null
let starttime = Date.now()
return function () {
let curTime = Date.now() //
let remaining = delay - (curTime - starttime) //
let context = this
let args = arguments
clearTimeout(timer)
if (remaining <= 0) {
fn.apply(context, args)
starttime = Date.now()
} else {
timer = setTimeout(fn, remaining);
}
}
}
防抖
简单的封装:
javascript
function debounce(func, wait) {
let timeout;
return function () {
let context = this; // this
let args = arguments; // event
clearTimeout(timeout)
timeout = setTimeout(function () {
func.apply(context, args)
}, wait);
}
}
防抖和节流的相同点:
- 都可以使用setTimeout实现
- 目的都是降低回调函数的执行频率,节省计算资源
不同的是:
- 函数防抖,在连续操作结束后,处理回调,利用clearTimeout和setTimeout实现;函数节流是在一段时间只执行一次,
- 防抖关注的是一段时间内频繁触发的事件,只在最后执行一次;节流值关注的事一段时间内执行一次。
应用场景
防抖的使用场景有:
- 搜索框输入,只需要用户最后一次输入完,再做处理
- 手机号、邮箱验证输入检测
- 窗口大小resize,只需窗口调整完成后,计算窗口的大小,防止重复渲染
节流的应用场景有:
- 滚动加载,加载更多或者滚动到底部监听
- 搜索框,搜索关联功能