一文学会JavaScript如何手写防抖节流

一、什么是防抖和节流
1、防抖(Debounce):
定义:在事件触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
应用场景:输入框实时搜索、窗口调整等。
实现思路:通过定时器实现,如果在规定时间内再次触发事件,则清除上一次的定时器并重新设置。
2、节流(Throttle):
定义:对于连续多次触发的事件,每隔一段固定时间执行一次。

应用场景:鼠标点击、监听滚动事件、input输入等。
实现思路:通过记录上次执行的时间戳,判断当前时间与上次时间的差值是否大于设定的间隔时间,如果是则执行函数。
二、防抖的实现
基本版
function debounce(fn, delay) {
let timer;
return function() {
clearTimeout(timer);
timer = setTimeout(fn, delay);
}
}
闭包优化版
function debounce(fn, delay) {
let timer;
return function() {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(context, args);
}, delay);
}
}
立即执行增强版
function debounce(fn, delay) {
let timer;
let isImmediatelyInvoked = false;
return function() {
const context = this;
const args = arguments;
if (!isImmediatelyInvoked) {
fn.apply(context, args);
isImmediatelyInvoked = true;
}
clearTimeout(timer);
timer = setTimeout(function() {
isImmediatelyInvoked = false;
}, delay);
}
}
三、节流的实现
时间戳版
function throttle(fn, wait) {
let preTime = 0;
return function() {
const context = this;
const args = arguments;
const now = +new Date();
if (now preTime > wait) {
fn.apply(context, args);
preTime = now;
}
}
}
定时器版
function throttle(fn, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
if (!timeout) {
timeout = setTimeout(function() {
fn.apply(context, args);
timeout = null;
}, wait);
}
}
}
组合版
function throttle(fn, wait) {
let preTime = 0;
let timeout;
return function() {
const context = this;
const args = arguments;
const now = +new Date();
const remaining = wait (now preTime);
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
preTime = now;
fn.apply(context, args);
} else if (!timeout) {
timeout = setTimeout(function() {
preTime = +new Date();
timeout = null;
fn.apply(context, args);
}, remaining);
}
}
}
四、自定义版节流
在组合版的基础上,设置一个options对象参数,根据传的值判断要哪一种效果,规定:
leading: false表示禁用第一次执行。

trailing: false表示禁用停止触发的回调。
function throttle(fn, wait, options = {}) {
let timeout;
let preTime = 0;
const leading = options.leading === false;
const trailing = "trailing" in options ? options.trailing : true;
return function() {
const context = this;
const args = arguments;
const now = +new Date();
if (!leading && now < preTime) return; // 禁用第一次执行
const remaining = wait (now preTime);
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
preTime = now;
fn.apply(context, args);
if (!trailing) return; // 禁用停止触发的回调
} else if (!timeout) {
timeout = setTimeout(function() {
preTime = +new Date();
timeout = null;
fn.apply(context, args);
}, remaining);
}
}
}
五、相关问题与解答栏目
1. 什么时候使用防抖和节流?它们有什么区别?
解答:防抖和节流都是用于限制高频事件触发的性能优化手段,防抖是将多次事件触发合并为最后一次触发,适用于输入框搜索、窗口调整等场景;而节流是每隔一段时间只执行一次事件,适用于滚动事件、鼠标移动等场景,具体选择哪种方式取决于实际需求。
如何在项目中应用防抖和节流?
解答:可以通过将防抖或节流函数封装后绑定到相应的事件上来实现,对于输入框的实时搜索功能,可以使用防抖函数来减少搜索请求的次数;对于滚动加载更多数据的功能,可以使用节流函数来控制数据加载的频率,具体实现可以参考上述代码示例。
各位小伙伴们,我刚刚为大家分享了有关“一文学会JavaScript如何手写防抖节流”的知识,希望对你们有所帮助。如果您还有其他相关问题需要解决,欢迎随时提出哦!











