事件节流,函数防抖
防抖(Debouncing)
概念:防抖技术是指在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。防抖确保了一个事件处理函数在一定时间内只执行一次。
作用:防抖常用于输入框搜索、窗口大小调整、滚动事件等场景,这些场景下事件可能会非常频繁地触发,但并不需要每次触发都执行相应的处理函数。防抖可以减少不必要的计算或DOM操作,提高性能。
使用场景:
搜索框实时搜索建议(用户停止输入后才开始搜索)
窗口大小调整时重新布局(窗口大小调整停止后才开始重新布局)
滚动事件监听(滚动停止后执行某些操作)
/*
*
* 事件节流函数
*
* 该函数用于限制函数的执行频率,确保函数在指定的时间间隔内最多执行一次。
* 这在处理如滚动、窗口大小调整等高频事件时非常有用,以避免性能问题。
*
* @param {Function} func - 需要进行节流的函数。
* @param {number} delay - 节流的时间间隔,以毫秒为单位。
* @returns {Function} - 返回一个新的函数,这个新函数是func的节流版本。
*/
function tool_throttle(func, delay) {
var timer = null; // 用于存储setTimeout的定时器ID,以便在需要时清除它。
var startTime = Date.parse(new Date()); // 记录上一次执行func的时间戳(但这里的实现方式并不完全准确,因为它只记录了一次开始时间)。
// 返回一个新的函数,这个函数将作为func的节流版本被调用。
return function() {
var curTime = Date.parse(new Date()); // 获取当前时间戳。
// 计算距离上次执行func还有多少时间。
// 但注意,这里的实现方式有误,因为它没有正确反映func实际执行的时间间隔。
// 更准确的方式是记录上一次执行func后的时间戳,而不是只记录一个开始时间。
var remaining = delay - (curTime - startTime);
var context = this; // 保存调用上下文,以便func能够以正确的this值执行。
var args = arguments; // 保存调用参数,以便func能够接收到正确的参数。
// 清除之前的定时器(如果存在),以避免重复执行。
clearTimeout(timer);
// 如果剩余时间小于等于0,说明已经到了执行func的时间,或者已经超过了设定的时间间隔。
if (remaining <= 0) {
func.apply(context, args); // 执行func,并传入正确的上下文和参数。
// 更新startTime为当前时间戳(但这里并不准确,因为理想情况下应该记录func执行完成后的时间)。
startTime = Date.parse(new Date());
} else {
// 如果还没到执行func的时间,则设置一个定时器,在剩余时间后执行func。
timer = setTimeout(function() {
func.apply(context, args);
}, remaining);
// 注意:这里的setTimeout实际上并不会精确地在remaining毫秒后执行,
// 因为JavaScript的事件循环和定时器解析可能会有一定的延迟。
}
};
}
// 注意:上述实现虽然可以工作,但关于startTime的处理并不完全符合节流函数的典型实现。
// 更常见的做法是在每次执行func后更新一个“上次执行时间”的变量,而不是仅记录一个开始时间。
节流(Throttling)
概念:节流技术是指在规定时间内,只执行一次函数。如果这个单位时间内触发多次函数,只有一次能生效。节流通过减少函数的执行次数来达到性能优化的目的。
作用:节流常用于控制一些频繁执行但不需要每次都响应的事件,如滚动事件、鼠标移动事件等。通过节流,可以控制这些事件的处理函数在固定时间间隔内只执行一次,从而避免因为过于频繁的执行而导致的性能问题。
使用场景:
滚动加载(滚动时不是每次滚动都加载,而是在滚动停止一段时间后加载)
游戏中的射击(控制射击频率,避免因为快速点击而导致的性能问题)
实时数据监控(如实时日志监控,不需要每秒都刷新数据,可以设定每5秒刷新一次)
/**
* 函数防抖(Debounce)
*
* 该函数用于限制回调函数的执行频率,确保回调函数在事件被触发n秒后再执行,
* 如果在这n秒内又被触发,则重新计时。这常用于处理如窗口大小调整、输入框内容校验等事件。
*
* @param {Function} fn - 需要进行防抖处理的回调函数。
* @param {number} delay - 延迟时间,单位毫秒,表示回调函数被触发后需要等待的时间。
* @returns {Function} - 返回一个新的函数,这个新函数是fn的防抖版本。
*/
function tool_debounce(fn, delay) {
// 维护一个定时器变量,用于存储setTimeout返回的ID,以便在需要时能够清除它。
let timer = null;
// 返回一个新的函数,这个新函数将作为fn的防抖版本被调用。
return function() {
// 通过 ‘this’ 和 ‘arguments’ 获取原始函数被调用时的上下文和参数。
// 这样做是为了确保防抖函数执行时,能够以正确的上下文和参数调用原始函数。
let context = this; // 保存调用上下文
let args = arguments; // 保存调用参数
// 如果已经存在定时器,则清除它,这样可以确保如果事件在短时间内被连续触发,
// 那么之前的等待将被取消,重新开始计时。
clearTimeout(timer);
// 设置一个新的定时器,在指定的延迟时间后执行原始函数。
timer = setTimeout(function() {
// 使用apply方法来调用原始函数,确保能够正确地传入上下文和参数。
fn.apply(context, args);
}, delay);
};
}
// 使用示例:
// 假设有一个需要防抖处理的函数updatePosition,它根据鼠标位置更新页面元素的位置。
// function updatePosition(x, y) {
// console.log(`Mouse position updated to (${x}, ${y})`);
// }
// 使用tool_debounce函数创建updatePosition的防抖版本。
// const debouncedUpdatePosition = tool_debounce(updatePosition, 250);
// 现在,你可以将debouncedUpdatePosition绑定到如mousemove事件上,
// 它将确保updatePosition函数在鼠标停止移动后250毫秒内只被调用一次。
总结
- 防抖:确保函数在事件停止触发一定时间后才执行,减少不必要的执行次数。
- 节流:在固定时间间隔内只执行一次函数,控制函数的执行频率。
选择使用防抖还是节流,主要取决于具体的应用场景和需求。防抖更适用于那些需要等待用户操作停止后再执行的任务,如搜索建议、窗口大小调整等;而节流则更适用于那些需要控制执行频率,但又不希望完全停止执行的任务,如滚动加载、游戏射击等。