在前端开发中,我们经常会遇到这样的情况:某些事件(如滚动、输入、点击等)会频繁触发,如果不加以控制,可能会导致性能问题。Vue3 中的防抖(Debounce)和节流(Throttle)就是用来解决这类问题的两种常用技术。
一、什么是防抖和节流?
1. 防抖(Debounce)
什么是防抖?
就像我们按电梯按钮,不管你按多少次,电梯只会在你松手一段时间后才会启动。
当事件触发时,不立即执行处理函数,而是等待一段时间(比如300ms)。如果在这段时间内事件再次触发,则重新计时。只有在指定时间内事件不再触发,才会真正执行处理函数。
适用场景:
1、搜索框输入联想(避免每次按键都发送请求)
2、窗口大小调整事件
3、按钮点击防重复提交
2. 节流(Throttle)
什么是节流?
当我们滚动页面时,可能需要执行某些操作,比如懒加载图片、检测滚动位置等。如果不加限制,滚动事件会非常频繁地触发,导致性能问题。
在固定的时间间隔内(比如300ms),无论事件触发多少次,处理函数只会执行一次。
适用场景:
1、滚动事件
2、鼠标移动事件
3、游戏中的连续按键处理
二、简单实现
1. 防抖的简单实现
function debounce(func, delay) {
let timer = null;
return function(...args) {
// 如果已经有计时器,先清除
if (timer) clearTimeout(timer);
// 设置新计时器
timer = setTimeout(() => {
func.apply(this, args);
timer = null; // 执行后重置
}, delay);
}
}
Vue3 组件示例:
<script setup>
import { ref } from 'vue';
const searchQuery = ref('');
// 创建防抖函数
const debouncedSearch = debounce((query) => {
console.log('执行搜索:', query);
// 这里可以调用API
}, 500);
const handleInput = (e) => {
searchQuery.value = e.target.value;
debouncedSearch(searchQuery.value);
};
</script>
<template>
<input @input="handleInput" placeholder="搜索..." />
</template>
2. 节流的简单实现
function throttle(func, delay) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= delay) {
func.apply(this, args);
lastTime = now;
}
}
}
Vue3 组件示例:
<script setup>
import { ref } from 'vue';
const scrollPosition = ref(0);
// 创建节流函数
const throttledScroll = throttle(() => {
scrollPosition.value = window.scrollY;
console.log('滚动位置:', scrollPosition.value);
}, 200);
const handleScroll = (e) => {
throttledScroll();
};
</script>
<template>
<div @scroll="handleScroll" style="height: 200px; overflow-y: scroll;">
<!-- 很多内容 -->
<div v-for="i in 100" :key="i">内容 {{ i }}</div>
</div>
</template>
三、更健壮的实现(包含取消功能)
实际开发中,我们可能需要取消防抖/节流操作,比如组件卸载时清理定时器。
1. 带取消功能的防抖
function debounce(func, delay) {
let timer = null;
// 返回一个函数对象,包含执行方法和取消方法
const debounced = function(...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
// 添加取消方法
debounced.cancel = function() {
clearTimeout(timer);
timer = null;
};
return debounced;
}
Vue3 组件中使用:
<script setup>
import { onUnmounted, ref } from 'vue';
const searchQuery = ref('');
let debouncedSearch = null;
onUnmounted(() => {
// 组件卸载时取消防抖
if (debouncedSearch) debouncedSearch.cancel();
});
debouncedSearch = debounce((query) => {
console.log('执行搜索:', query);
// 这里可以调用API
}, 500);
const handleInput = (e) => {
searchQuery.value = e.target.value;
debouncedSearch(searchQuery.value);
};
</script>
四、使用 Lodash 库
如果你不介意使用第三方库,Lodash 提供了更完善的实现:
npm install lodash
或
yarn add lodash
使用示例:
import { debounce, throttle } from 'lodash';
// 防抖
const debouncedFn = debounce(() => {
console.log('防抖执行');
}, 300);
// 节流
const throttledFn = throttle(() => {
console.log('节流执行');
}, 300);
Vue3 中使用:
<script setup>
import { onUnmounted } from 'vue';
import { debounce } from 'lodash';
const handleSearch = debounce((query) => {
console.log('搜索:', query);
}, 300);
const onInput = (e) => {
handleSearch(e.target.value);
};
onUnmounted(() => {
// 取消防抖
handleSearch.cancel();
});
</script>
五、总结
1、什么时候用防抖?什么时候用节流?
使用防抖:
1、用户停止输入后再搜索(搜索框)
2、窗口大小调整完成后再调整布局
3、按钮点击防止重复提交
使用节流:
1、滚动事件(如无限滚动加载)
2、鼠标移动事件(如拖拽操作)
3、游戏中的连续按键
特性区别
特性 | 防抖 | 节流 |
---|---|---|
触发时机 | 事件停止触发后一段时间执行 | 固定时间间隔内最多执行一次 |
行为 | 重置计时器 | 固定间隔执行 |