防抖和节流是前端开发中常用的优化方法,用于控制函数的执行频率。
防抖
防抖 (debouncing) 是一种编程技巧,主要用于防止一个事件被频繁触发。在一段时间内,只有最后一次触发该事件才会被执行。防抖是一种常用的用户体验优化技巧,可以使网页在用户互动过程中更流畅。
例如,在一个输入框中,防抖可以防止频繁的输入导致的频繁请求,每次请求只在最后一次输入后统一发出。
通常使用 setTimeout() 函数实现防抖,在频繁触发事件时,每次触发事件后清除上一次未执行的定时任务,再重新安排一个新的定时任务,从而保证事件的最后一次触发才会被执行。
手写防抖
//一个被防抖的函数 func
//一个默认等待时间 wait(默认为 500ms)
function debounce(func,wait=500){ //默认等待时间
let timeout
let debounced = function(){
//如果有定时任务,准备从新开始计时
if (timeout) clearTimeout(timeout);
//如果没有定时任务,则从现在开始安排定时任务
timeout = setTimeout(() => {
func.apply(this, arguments);
}, wait);
}
//注意最后返回的是一个被防抖过的函数
return debounced
}
防抖举例
防抖的举例:
假设我们有一个搜索框,当用户输入的时候,我们希望在用户输入完成之后一段时间内不再触发请求,以避免过多的请求。我们可以通过防抖来实现这一目的。
例如:
const searchBox = document.querySelector("#search");
//防抖函数
function debounce(func, wait) {
let timeout;
return function() {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, arguments);
}, wait);
};
}
//请求函数
function requestData() {
console.log("请求数据");
}
searchBox.addEventListener("input", debounce(requestData, 500));
这样,当用户在输入搜索关键字时,只有在用户输入完成后 500 毫秒内没有再次输入时,才会请求数据。
节流
节流,即在一定时间内限制函数的执行次数,多余的调用将被忽略,只有在规定的时间内执行一次。这种技术在用户交互响应、动画等需要频繁触发的事件处理场景中有着广泛的应用。
例如:在用户拖拽窗口的过程中,我们不需要随着用户的每一次操作都重新渲染界面,而是只在操作完成后渲染一次;或者在用户输入搜索内容时,我们不需要随着每一个字符的输入都请求后台,而是在用户输入完成后,等待一段时间再请求后台。
实现方法有多种,常见的有时间戳版本和定时器版本。时间戳版本通过记录函数最后一次被调用的时间,并在每次调用时判断当前时间与最后一次调用时间的差值是否大于规定的时间间隔。定时器版本通过记录函数被调用时设置的定时任务,并在每次调用时判断定时任务是否存在,如果存在则不触发函数,如果不存在则触发函数并设置定时任务。
//实现1:时间戳
// 第一次会触发,最后一次不会触发 [内心更加认可]【推荐】
function throttle1(func, wait) {
let old = 0; //上一次触发的时间
return function () {
let now = +new Date(); //+new Date()日期对象隐式转换为时间戳整数
if (now - old > wait) {
old = now;
func.apply(this, arguments);
}
}
}
//实现2:
// 第一次不会触发,最后一次会触发
function throttle2(func, wait) {
let timeout;
return function () {
if (!timeout) {
timeout = setTimeout(() => {
func.apply(this, arguments);
timeout = null;
}, wait)
}
}
}
防抖和节流是两种不同的技术,它们都是为了解决对函数过于频繁调用的问题。不同点如下:
1.防抖(Debouncing): 在某一段时间内,如果有很多次事件的触发,只有在这一段时间结束后才执行函数一次。
2.节流(Throttling): 在某一段时间内,只执行函数一次,即使有多次事件的触发,在这一段时间内只会执行一次。
总结来说,防抖是在某一段时间内等待事件的触发,如果在这一段时间内有多次事件的触发,只会在这一段时间结束后执行一次函数;而节流是在某一段时间内只执行函数一次,即使有多次事件的触发,也只会在这一段时间内执行一次函数