代码节流和防抖是前端开发中常用的技巧,可以提高页面性能和用户体验。接下来,我将以“手把手”的方式为你详细介绍如何实现代码节流和防抖。
? 首先,我们来了解一下什么是代码节流和防抖。
代码节流(Throttling)是指降低事件触发频率的一种手段。当一个事件被触发后,在一定时间间隔内,不管事件再次触发多少次,都只会执行一次函数。
代码防抖(Debouncing)与节流相似,但是它允许事件在一定时间间隔内的连续触发,只是等待一段时间后才执行函数。
🔧 接下来,我们开始实现代码节流和防抖。
1?? 首先实现函数节流的工具函数。
函数节流用于限制某些频繁触发的操作(如
resize
和scroll
事件)的执行频率。
该函数接收四个参数:delay
、noTrailing
、callback
和debounceMode
,并返回一个新的节流函数。
delay
: 节流的延迟时间,单位为毫秒。noTrailing
: 可选参数,默认为false
。如果设为true
,表示当节流函数被调用时,每过delay
毫秒callback
也会执行一次。如果设为false
或未传入,则callback
将在最后一次调用节流函数后执行一次。callback
: 延迟毫秒后执行的函数。在执行节流功能时,callback
会按原样传递this
上下文和所有参数。debounceMode
: 可选参数,默认为false
。如果设为true
,则clear
函数会在delay
毫秒后执行;如果设为false
,则callback
函数会在delay
毫秒后执行。以下是代码:
/**
* @desc 函数节流。
* 适用于限制`resize`和`scroll`等函数的调用频率
* @param {Number} delay 0 或者更大的毫秒数。对于事件回调,建议使用100到250毫秒之间的延迟。
* @param {Boolean} noTrailing 可选,默认为false。
* 如果noTrailing为true,当节流函数被调用时,每过`delay`毫秒,`callback`也将执行一次。
* 如果noTrailing为false或未传入,`callback`将在最后一次调用节流函数后执行一次。
* @param {Function} callback 延迟毫秒后执行的函数。`this`上下文和所有参数都是按原样传递的,执行节流功能时,调用`callback`。
* @param {Boolean} debounceMode 如果`debounceMode`为true,`clear`将在`delay`ms之后执行。
* 如果`debounceMode`为false,`callback`将在`delay`ms之后执行。
* @return {Function} 新的节流函数
*/
module.exports = function throttle(delay, noTrailing, callback, debounceMode) {
var timeoutID; // 超时ID,在停止调用包装器后,确保在适当的时间执行`callback`
var lastExec = 0; // 记录最后一次执行`callback`的时间
// 如果没有传入`noTrailing`参数,则根据参数顺序重新赋值
if (typeof noTrailing !== 'boolean') {
debounceMode = callback;
callback = noTrailing;
noTrailing = undefined;
}
// `wrapper`函数封装了节流和防抖的功能,当执行该函数时,会限制`callback`的执行频率。
function wrapper() {
var self = this;
var elapsed = Number(new Date()) - lastExec;
var args = arguments;
// 执行`callback`并更新`lastExec`时间戳
function exec() {
lastExec = Number(new Date());
callback.apply(self, args);
}
// 如果`debounceMode`为true(在开始时),用于清除标记以允许未来的`callback`执行。
function clear() {
timeoutID = undefined;
}
// 如果处于防抖模式并且没有之前的延迟,执行`callback`
if (debounceMode && !timeoutID) {
exec();
}
// 清除任何现有的超时
if (timeoutID) {
clearTimeout(timeoutID);
}
// 如果处于节流模式,并且超过了延迟时间,则执行`callback`
else if (debounceMode === undefined && elapsed > delay) {
exec();
}
// 在尾部节流模式下,由于未超过延迟时间,根据最近一次执行后的时间调度`callback`执行
else if (noTrailing !== true) {
timeoutID = setTimeout(debounceMode ? clear : exec, debounceMode === undefined ? delay - elapsed : delay);
}
}
// 返回封装函数`wrapper`
return wrapper;
};
2?? 实现函数防抖的工具函数
?debounce?
的函数,该函数接收三个参数:?delay
?、?immediate
?和 ?callback
?。以下是防抖函数的案例:
/**
* @desc 函数防抖。
* 适用于限制`resize`和`scroll`等函数的触发频率
*
* @param {Number} delay 0 或者更大的毫秒数。对于事件触发,建议使用100到250毫秒之间的延迟。
* @param {Boolean} immediate 可选,默认为false。
* 如果immediate为true,在延迟开始前调用,将会立即执行一次该函数。
* 如果immediate为false或未传入,在延迟结束后调用。
* @param {Function} callback 延迟毫秒后执行的函数。`this`上下文和所有参数都是按原样传递的,执行防抖功能时,调用`callback`。
* @return {Function} 新的防抖函数
*/
function debounce(delay, immediate, callback) {
let timer = null;
return function () {
const context = this;
const args = arguments;
clearTimeout(timer);
if (immediate && !timer) {
callback.apply(context, args);
}
timer = setTimeout(function () {
timer = null;
if (!immediate) {
callback.apply(context, args);
}
}, delay);
};
}
使用防抖函数将会在规定的延迟时间内,只执行最后一次触发的函数回调。可以通过设置delay
参数来控制延迟的毫秒数,通过设置immediate
参数来确定是否立即执行一次函数回调。
标签:#代码节流 #代码防抖 #前端开发 #优化性能