防抖 Debounce
- 防抖(Debounce)是一种常用的前端优化技术,用于限制在事件频繁触发时执行回调函数的次数。当一个事件被触发后,如果在一定的时间间隔内又被触发,那么只有最后一次触发的事件会执行回调函数,而之前的事件将被忽略。
- 防抖的主要思想是延迟执行回调函数,在每次触发事件后设置一个定时器,在指定的时间间隔内没有再次触发事件时,才执行回调函数。如果在该时间间隔内又触发了事件,则重新设置定时器,取消之前的定时器。
防抖的应用场景包括但不限于:
- 输入框搜索联想:在用户连续输入时,避免频繁地触发搜索请求,而是在用户停止输入一段时间后再发起搜索请求。
- 窗口大小调整:在窗口大小调整过程中,避免频繁地更新布局,而是在用户停止调整窗口大小后再执行布局更新操作。
- 按钮点击防重复:在按钮被快速点击多次时,避免多次提交请求或执行操作,而是只响应最后一次点击。
防抖函数精简版:
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
function callback() {
console.log('Debounced function is called');
}
const debouncedFn = debounce(callback, 300);
document.addEventListener('scroll', debouncedFn);
- 在上面的示例中,我们定义了一个防抖函数
debounce,它接受两个参数:func 是需要进行防抖的回调函数,delay 是延迟时间(以毫秒为单位)。
- 在返回的函数中,我们使用
setTimeout 来延迟执行回调函数 func。如果在延迟期间再次调用了返回的函数,我们会清除之前的定时器,重新设置新的定时器,确保在最后一次调用后的一段时间内没有新的调用才执行回调函数。
- 在示例中,我们定义了一个回调函数
callback,它在防抖后被调用时会输出一条消息。
- 通过使用防抖函数,我们将回调函数
callback 使用 debounce 包装,并将得到的防抖函数赋值给变量 debouncedFn。然后,我们在需要进行防抖的事件上(此处为 scroll 事件)绑定防抖函数 debouncedFn。
- 这样,当滚动事件触发时,防抖函数会被调用,但实际上只有在停止滚动一段时间后才会执行回调函数。这样可以避免在频繁滚动时频繁触发回调函数,提升性能并避免不必要的操作。
节流 Throttling
- 节流(Throttling)是一种限制函数执行频率的技术。它确保在一定时间间隔内,函数只能执行一次。
- 节流的基本思想是,当触发事件时,如果在设定的时间间隔内函数已经被调用过了,则忽略该次触发,直到过了设定的时间间隔后,函数才会再次执行。
- 节流的主要作用是减少函数的执行次数,特别是在高频率触发的事件中,如滚动、窗口调整等。通过控制函数的执行频率,可以降低事件处理的资源消耗,提升性能,并且避免在短时间内多次执行函数导致的不必要的操作。
示例:
下面的代码实现了一个基本的节流函数 throttle
const throttle = (fn, ms = 0) => {
let start = 0
return function(...args){
let now = Date.now()
if (now - start >= ms){
fn.apply(this, args)
start = Date.now()
}
}
}
- 在节流函数内部,定义了一个
start 变量,初始值为 0。该变量用于记录上一次函数执行的时间戳。
- 返回的函数使用了剩余参数语法
...args,以便可以接收任意数量的参数。
- 在返回的函数内部,首先获取当前的时间戳,使用
Date.now() 方法可以得到当前时间距离 1970 年 1 月 1 日的毫秒数。
- 接下来,计算当前时间戳
now 与上一次函数执行的时间戳 start 的时间差。如果时间差大于等于设定的时间间隔 ms,则执行函数。
- 接下来,计算当前时间戳
now 与上一次函数执行的时间戳 start 的时间差。如果时间差大于等于设定的时间间隔 ms,则执行函数。
定时器版本:
const throttle = (fn, ms = 0) => {
let timerId
return function (...args) {
if (timerId) return
timerId = setTimeout(() => {
fn.call(this, ...args)
timerId = null
}, ms);
}
}
- 在节流函数中,我们定义了一个
timerId 变量,并将其初始值设置为 undefined。
- 返回的函数使用了剩余参数语法
...args,以便可以接收任意数量的参数
- 在返回的函数内部,首先检查
timerId 的值。如果存在值(即不为 undefined),表示已经设置了定时器并处于等待执行状态,直接返回,不再开启新的定时器。这是为了避免在时间间隔内连续调用时重复触发函数的执行
- 如果
timerId 为 undefined,表示定时器未设置,可以执行函数。于是,我们使用 setTimeout 开启一个定时器,延迟执行函数。在定时器回调函数中,我们调用原始的函数 fn,使用 call 方法传递正确的上下文(this)和参数(...args)。然后,将 timerId 设置为 null,表示定时器已执行完毕。
- 通过这样的实现,我们实现了一个基本的节流函数。它能确保在设定的时间间隔内只执行一次函数,避免过于频繁的调用。当连续调用时,只有在时间间隔经过后才会再次执行函数。
lodash实现节流防抖
<div class="box"></div>
<script src="./js/lodash.min.js"></script>
<script>
const box = document.querySelector('.box')
let i = 0
const move = (x, y) => {
i++
box.innerHTML = i
}
box.addEventListener('mousemove', _.debounce(move, 300))
box.addEventListener('mousemove', _.throttle(move, 300))
</script>
- 去lodash网址下载js文件
- 引入文档
- _.debounce(move, 300) 或 _.throttle(move, 300)