防抖(debounce)
什么是防抖?
比喻一下:我频繁地敲击键盘,你就敲吧,等你敲完最后一下,我们再进行下一步操作
防抖的字面意思就是防止抖动,比如当我们写一个输入框的时候,每次键盘的敲击都带来整个页面的反应,试想下频繁的敲击是不是就会带来页面的“抖动”。
所以防抖的原理就是:在事件触发n秒后再执行回调函数,如果在这n秒内再次触发事件,则重新计时。
举个例子:
const printSomething = function(){
for(let i = 0;i < 10;i++){
console.log('i--------', i);
}
};
// 获取输入框dom
const inputBox = document.getElementById('input')
inputBox.addEventListener('keyup', (e) => {
printSomething();
})
如果像上面一样写代码,只要键盘有敲击便会无节制地执行回调函数,当然这里的回调函数很简单,只是打印0-10而已,试想如果回调函数需要打印0-100000呢?如此多的回调函数入栈必然会导致页面宕机。针对这种情况,我们希望的是:“只在最后一次敲击键盘后去执行回调函数”(你别抖了!),顺着这个想法,我们来改造一下:
const printSomething = function(){
for(let i = 0;i < 10;i++){
console.log('i--------', i);
}
};
function debounce(func, delay){
let timer = null;
clearTimeout(timer);
timer = setTimeout(function(){
func();
}, delay);
}
// 获取输入框dom
const inputBox = document.getElementById('input')
inputBox.addEventListener('keyup', (e) => {
printSomething();
})
防抖的应用场景
- 搜索框实时搜索:当用户在搜索框中输入关键字时,防抖可以在用户输入完毕后一段时间内才触发搜索请求,避免频繁地请求搜索数据,提高搜索性能和用户体验。
- 窗口大小调整:当用户调整浏览器窗口大小时,防抖可以避免频繁地触发响应,以提高页面性能和用户体验。
- 按钮点击事件:当用户点击按钮时,防抖可以避免多次点击,以防止意外的操作和减轻服务器负担。
- 滚动加载:当用户滚动页面时,防抖可以避免频繁地触发加载请求,减轻服务器负担和提高用户体验。
- 实时数据更新:当数据源实时更新时,防抖可以避免频繁地触发数据更新,以避免过多的请求和资源浪费。
手写防抖
通过对防抖的介绍,我们可以大致归纳出,手写一个防抖函数需要以下几个关键点:
- 接收两个参数,一个是“抖动结束后的执行函数”func,一个是最小防抖时间单位
- 使用一个计时器
setTimeout来实现延迟操作 - 返回一个新函数,新函数会在延迟时间内等待,如果延迟时间内没有再次触发,则去执行
func,如果触发了,则setTimeout重新开始计时 - 外部会对防抖函数频繁调用,所以
debounce函数会执行多次
function debounce(func, delay) {
let timeId;
return function(...args) {
if(timeId) {
clearTimeout(timeId);
}
timeId = setTimeout(() => {
func.apply(this, args);
}, delay)
}
}
节流(throttle)
什么是节流?
比喻一下:省点水吧~,我一分钟只开一下水闸,你拧多少次水龙头都没用
节流指的是在一定时间内只执行一次事件处理函数。如果在这段时间内多次触发事件,只有第一次触发的事件会执行处理函数,后面的事件会被忽略。节流可以减少事件处理函数的执行次数,提高性能和响应速度。
节流的应用场景
- 监听滚动事件:当用户在网页中滚动页面时,会不断触发滚动事件。如果在滚动事件中执行大量操作,会导致页面卡顿和性能问题。可以使用节流技术,限制滚动事件处理函数的调用次数,以提高性能和用户体验。
- 搜索框输入事件:当用户在搜索框中输入关键字时,会触发输入事件,以便动态搜索相关结果。如果在每次输入事件中都发送请求,会导致不必要的请求和服务器资源的浪费。可以使用节流技术,在一定时间内限制输入事件处理函数的调用次数,以减少请求和提高性能。
- 窗口大小调整事件:当用户调整浏览器窗口的大小时,会触发窗口调整事件。如果在窗口调整事件中执行大量操作,会导致页面卡顿和性能问题。可以使用节流技术,限制窗口调整事件处理函数的调用次数,以提高性能和用户体验。
- 监听鼠标移动事件:当用户在网页中移动鼠标时,会触发鼠标移动事件。如果在每次鼠标移动事件中执行大量操作,会导致页面卡顿和性能问题。可以使用节流技术,限制鼠标移动事件处理函数的调用次数,以提高性能和用户体验。
手写节流
实现节流的关键点与防抖有相似之处,关键区分在于函数的执行时机不同
- 节流函数接收两个入参,执行函数
func与延迟时间delay - 页面第一次进到节流函数的逻辑内,会直接执行
func,并开始计时delay - 在一次
func执行之后的延迟时间delay内,不再触发func的执行
// 节流函数
function throttle(func, delay) {
let timer = 0;
return function (...args) {
if (timer) {
return;
}
timer = setTimeout(() => {
fn.apply(this, args)
timer = 0;
}, delay)
}
}
此外,我们还可以用时间戳的方式来实现节流
function throttle(func, delay){
let lastTime = 0;
return function (...args) {
const now = new Date().getTime();
const timeDiff = now - lastTime;
if (!lastTime || timeDiff > delay){
lastTime = now;
func.apply(this, args);
}
}
}
以上代码中,throttle函数接受两个参数:一个函数func和一个延迟时间delay,并返回一个新的函数。新函数会在指定的延迟时间内等待,如果在这段时间内再次调用新函数,则不会执行原始函数func,直到这段时间过去。
在新函数中,我们首先获取当前时间戳,计算当前时间与上一次调用时间的时间差。如果时间差大于或等于延迟时间delay,则执行原始函数func并更新上一次调用时间lastTime。
const button = document.getElementById('my-button');
button.addEventListener('click', throttle(function () {
console.log('Button clicked');
}, 500));
在此示例中,当用户点击按钮时,throttle函数将原始函数console.log封装在内部,最多每500毫秒执行一次该函数。这可以避免在短时间内连续点击按钮导致的过多操作。
总结
防抖和节流同样都是一种用于优化Web应用程序性能的方式。
防抖和节流都能够优化Web应用程序的性能,但它们的应用场景和效果有所不同。一般而言,防抖适用于需要等待用户输入的场景,以避免频繁的请求或操作。节流适用于高频率触发事件的场景,以避免过度执行操作导致性能问题。
为了避免混淆,可以类比记忆,比如:
防抖:你别抖了~,等你抖完我们再继续下一步
节流:省点水吧~,我一分钟只开一下水闸,你拧多少次水龙头都没用