小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
Javascript 浅谈节流和防抖
前言
实习的时候有个需求是防止用户短时间内多次提交表单内容。想到两种方法,一个是做防抖的处理,一个是在提交后禁用按钮,等请求返回后再重新启用。然后去了解了节流和防抖的原理和实现。这篇文章主要是简单介绍一下节流和防抖。
一、概念
- 节流:在单位时间内,只执行一次回调函数,若在单位时间内多次调用,只有一次会生效。
- 防抖:事件被触发后延迟调用函数,若再次触发时,之前函数还没有被调用,则取消之前注册的回调函数并重新注册。
相同点:本质上都是以闭包的形式存在。
不同点:节流是将多次执行变成每隔一段时间执行一次。防抖是将多次执行合并为最后一次执行。
二、简单实现
- 节流
function throttle(fn, wait = 50) {
// pre为上一次触发回调的时间
let pre = 0
return function (...args) {
let context = this
let now = +new Date()
if (now - pre >= wait) {
pre = now;
fn.apply(context, args);
}
}
}
- 防抖
function debounce(fn, delay = 50) {
let timer = 0;
return function (...args) {
let context = this
if (timer) clearTimeout(timer)
timer = setTimeout(() => { fn.apply(context, args) }, delay);
}
}
- 节流和防抖的结合版
debounce 的问题在于它“太有耐心了”。试想,如果用户的操作十分频繁——他每次都不等 debounce 设置的 delay 时间结束就进行下一次操作,于是每次 debounce 都为该用户重新生成定时器,回调函数被延迟了不计其数次。频繁的延迟会导致用户迟迟得不到响应,用户同样会产生“这个页面卡死了”的观感。
为了解决防抖可能存在的用户体验上的问题,可以用 Throttle 来优化 Debounce。
主要的思路是:
当没有达到预定的时间间隔,采用防抖的策略
达到预定的时间间隔,立即执行一次回调函数,不论防抖策略执行与否。
function throttle(fn, delay) {
let last = 0, timer = null
return function (...args) {
let context = this
let now = +new Date()
if (now - last < delay) {
clearTimeout(timer)
timer = setTimeout(function () {
last = now
fn.apply(context, args)
}, delay)
} else {
last = now
fn.apply(context, args)
}
}
}