debounce
是一种限制函数执行频率的技术,它可以在事件触发后延迟一段时间再执行函数,如果在这个时间内再次触发该事件,则之前的计时器会被清除并重新开始计时。这样可以有效地控制函数的执行次数,避免频繁执行。
debounce
的原理就是利用了setTimeout
和clearTimeout
函数,通过定时器来延迟函数的执行,并能够在规定时间内清除之前的计时器,实现函数调用的控制。
在Vue中使用debounce
时,每次触发函数都会将之前的计时器取消,重新计时一段时间,只有当一定时间内没有再次触发函数时才会真正执行该函数。这样可以避免在用户快速操作时频繁调用函数导致页面卡顿等问题。
现在,我们来看下在Vue中如何使用debounce
?
- 首先,安装Lodash库,Lodash是一个JavaScript实用工具库,提供了很多常用的方法和函数,包括
debounce
。可以使用npm或者yarn等包管理器进行安装。
npm install --save lodash
- 在需要使用的组件中引入Lodash库,并将
_
赋值给一个变量
import _ from 'lodash'
- 在需要使用
debounce
的方法中,使用_.debounce
函数对该方法进行包装。例如:
methods: {
search: _.debounce(function() {
// 搜索逻辑
}, 500)
}
在上述例子中,search
方法会被延迟500毫秒执行,如果在这段时间内再次调用该方法,则上一次的调用会被取消并重新计时。
以下是一个简单的debounce
函数实现:
function debounce(func, delay) {
let timer = null;
return function() {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
func.apply(context, args);
}, delay);
};
}
该实现中,我们通过闭包来保存变量timer
,用于记录计时器的ID。在每次被调用时,先清除之前的计时器,并重新设置一个新的计时器,延迟一定时间后执行传入的函数。
Vue中的debounce
实现也类似,其源码如下所示(摘自Vue官方文档):
// from Vue.js 2.x source code
function _createFnInvoker(fn) {
function invoker() {
const args = arguments;
const vm = invoker.vm;
if (vm._isMounted) {
// 如果已经挂载,则立即执行传入的函数
return fn.apply(vm, args);
}
// 否则将函数作为一个 watcher 加入到队列中等待执行
vm.$nextTick(() => {
if (!invoker.canceled) {
fn.apply(vm, args);
}
});
}
invoker.cancel = () => {
invoker.canceled = true;
};
return invoker;
}
export function debounceAndMerge(fn) {
const invoker = _createFnInvoker(fn);
return function(...args) {
// 每次被触发时,都取消之前的计时器
invoker.cancel();
// 使用 setTimeout 延迟执行函数
window.setTimeout(() => {
invoker.apply(invoker, args);
}, 0);
};
}
Vue中的debounceAndMerge
函数使用了类似的方式来实现,同样利用了闭包保存函数调用的状态。每次被触发时,都会先取消之前设定的计时器,并设置一个新的计时器延迟一段时间后执行传入的函数。如果在这段时间内再次触发该函数,则会取消之前的计时器并重新设置计时器。
需要注意的是,在Vue中使用debounceAndMerge
时,传入的函数会被封装成一个 watcher,然后添加到队列中等待执行,而不是直接调用执行函数。这是因为Vue是基于响应式原理的框架,在数据变化后需要重新渲染视图,因此将函数封装成 watcher 可以保证在数据更新后才执行相应的操作,避免出现意料之外的情况。