防抖和节流是前端开发中常用的优化方法,用于控制函数的执行频率。
防抖
防抖 (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(); // 将当前的日期对象转换为时间戳整数
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);
}
};
}
function mytest(){
console.log(arguments)
}
mytest(1,2,3)
区别
防抖和节流都是为了解决频繁触发事件时带来的性能问题。但它们有一个明显的区别:
1.防抖(debouncing): 事件在一定时间内不再被触发时才执行。
2.节流(throttling): 在一定时间内只能触发一次事件。
比如说,你的网页上有一个搜索框,用户在输入搜索内容时会触发搜索事件。如果不对这个事件进行处理,很有可能每输入一个字符就触发一次搜索,这样会对服务器造成很大的压力。
如果使用防抖,比如说设置防抖时间为 1s,那么每当用户输入一个字符就会触发搜索事件,但是如果在 1s 内用户继续输入,则会重新开始计时。如果在 1s 内用户没有再次触发事件,则执行搜索。
如果使用节流,比如说设置节流时间为 1s,那么每隔 1s 就会触发一次搜索,不管用户输入了多少字符。
通俗地说,防抖是将多次执行变为最后一次执行;节流是将多次执行变为每隔一段时间执行一次。