函数防抖
一、概念
防抖和节流的概念并不是JS所特有的。他们是对函数持续调用时进行不同控制的两个概念。
用大白话来说,防抖就是防止用户手抖,从而避免用户无意间执行多次函数调用,进而导致一些意想不到的问题。
比如一个表单提交页面,在提交时用户不小心小手一抖,多次点击了提交按钮,好巧不巧后端又没有做幂等操作,这样就有可能有多条数据插入到数据库中了。
通过防抖可以实现在事件触发一定时间后没有再次触发同一时间时,再去执行相关的处理函数。
如果你去银行ATM机转账的时候观察就会发现,ATM机的数字输入键盘也做了防抖处理,你不能在很快的时间内连续输入2个同样的数字,必须等一定的时间之后才可以继续输入,这样做的好处是防止用户输入过快导致错误发生。
不信?那你去体验一下吧 😂
二、作用&应用场景
防抖主要能带来以下好处:
-
优化用户体验
-
提升页面性能
防抖的应用场景有:
-
输入框内容联想:适时反馈,减少服务器压力
-
window.resize:避免UI渲染阻塞,导致浏览器卡顿 -
表单提交:减少服务器压力,防范恶意触发
三、如何实现防抖?
如上面所述,防抖是对一段时间的判断。所以我们可以通过一个计时器来实现。
具体来说,就是通过setTimeout来指定一定时间后执行处理函数,如果在这之前事件再次触发,则清空计时器,重新计时。
来,先写第一版:
function debounce(fn, wait) {
let timerId = 0;
return function(...args) {
if (timerId) clearTimeout(timerId);
timerId = setTimeout(()=>{
fn.call(this, args);
}, wait);
}
}
// 调用
debounce(() => { console.log('触发函数调用')}, 200);
仔细观察会发现,方法调用后不会马上执行,而是等过了wait时间后才执行。那么如何才能首次触发立即执行呢?
function debounce(fn, wait) {
let timerId = 0;
return function(...args) {
if (timerId){
clearTimeout(timerId);
} else{
// 首次触发直接调用
fn.call(this, args);
}
timerId = setTimeout(()=>{
fn.call(this, args);
timerId = 0;
}, wait);
}
}
四、测试用例
可以使用监听用户键盘的input、窗口的resize等事件,也可以监听鼠标移动事件。
function test() {
var mousemove = debounce(() => { console.log('触发函数调用')}, 300);
document.addEventListener('mousemove', mousemove, false);
}
test();
函数节流
一、概念
再看节流,throttle。节流的概念可以想象一下水坝,你建了水坝在河道中,不能让水流动不了,你只能让水流慢些。换言之,你不能让用户的方法都不执行。如果这样干,就是debounce了。为了让用户的方法在某个时间段内只执行一次,我们需要保存上次执行的时间点与定时器。
函数节流会用在比input, keyup更频繁触发的事件中,如resize, touchmove, mousemove, scroll。throttle 会强制函数以固定的速率执行。因此这个方法比较适合应用于动画相关的场景。
二、实现
// 版本一:首次不执行,通过计时器实现
function throttle(fn, delay) {
let timerId = 0;
return function () {
if (timerId) return;
timerId = setTimeout(() => {
fn.apply(this, arguments);
timerId = 0;
}, delay);
};
}
// 首次执行,通过时间戳比较实现
function throttle2(fn, delay) {
let last = 0;
return function () {
let cur = +new Date();
if(cur - last > delay) {
fn.apply(this, arguments);
last = cur;
}
}
}
三、测试
function test() {
var mousemove = throttle(() => { console.log('触发函数调用')}, 500);
document.addEventListener('mousemove', mousemove, false);
}
test();
四、总结
如果还是不明白的话可以体验一下这个在线可视化比较工具。