防抖与节流
防抖(Debounce)和节流(Throttle)是前端开发中常用的两种优化手段,主要用于控制高频率触发的事件,避免过多的计算或者操作影响性能。
防抖(Debounce)
在事件被触发后,延迟指定时间才执行事件的处理函数,如果这段时间内时间再次被触发,则重新计时。
工作原理:
- 当事件被处罚时,设定一个定时器
- 如果在定时器到期前事件再次被处罚,则清除之前的定时器并重新设置
- 只有当事件停止触发切定时器到期后,目标函数才会执行
典型应用场景:
- 搜索框输入(等待用户停止输入后再发送请求)
- 窗口大小调整事件
- 表单验证(等用户完成输入后再验证)
代码示例
/**
* 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
let timeout = null;
export function debounce(func, wait = 500, immediate = false) {
// 清除定时器
if (timeout !== null) clearTimeout(timeout);
// 立即执行,此类情况一般用不到
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(function() {
timeout = null;
}, wait);
if (callNow) typeof func === 'function' && func();
} else {
// 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
timeout = setTimeout(function() {
typeof func === 'function' && func();
}, wait);
}
}
使用
<view class="debounce" @tap="$u.debounce(btnAClick, 500)"></view>
<script setup>
const toNext => {
...
}
...
debounce(toNext, 500)
...
</script>
节流(Throttle)
在一段时间内只允许时间处理函数执行一次,无论事件触发了多少次
工作原理:
- 当事件第一次触发式,执行函数并记录时间
- 在指定的时间间隔内,忽略所有后续触发
- 时间间隔过后,再次触发是会执行函数并重复上述过程
典型应用场景:
- 鼠标移动事件(当鼠标移动时,每隔一定时间执行一次处理函数)
- 滚动事件处理(当用户滚动页面时,每隔一定时间执行一次处理函数)
- 防止按钮重复点击
代码示例
/**
* 节流原理:在一定时间内,只能触发一次
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
let timer;
let flag;
export function throttle(func, wait = 500, immediate = true) {
if (immediate) {
if (!flag) {
flag = true
// 如果是立即执行,则在wait毫秒内开始时执行
typeof func === 'function' && func()
timer = setTimeout(() => {
flag = false
}, wait)
}
} else if (!flag) {
flag = true
// 如果是非立即执行,则在wait毫秒内的结束处执行
timer = setTimeout(() => {
flag = false
typeof func === 'function' && func()
}, wait)
}
}
使用
<view class="throttle" @click="throttle(handeSave, 1000)">提交</view>
<script setup>
const toNext => {
...
}
...
throttle(toNext, 500)
...
</script>
总结
如果需要在事件完全停止触发后才执行处理函数,使用防抖。
如果需要在时间频繁触发是控制执行频率,使用节流。
在实际开发中,可以根据具体需求选择合适的方式。(防止按钮重复点击,也可以给按钮加一个loading状态。)