原理是什么?
忽略重复事件,通过设置定时器,等待一定时间后执行事件处理函数,如果在这段时间内又触发了相同的事件,则重新计时。
用来解决什么问题
解决由于频繁触发事件引起的性能问题,例如表单提交,输入框搜索,页面滚动。
⚠️ 秒杀按钮是防抖吗? 答:不是,如果设置防抖那么大量的请求还是会在同一时间发过来,服务器还是会处理大量请求的压力。应该通过设置节流让他按照一定频率执行,因为用户没抢到是要一直抢的,如果使用防抖,用户的点击只会被响应一次,影响用户体验。。
表单提交一定会用防抖吗? 答:实际项目中一般在点击之后将按钮置为disable状态,防止用户的频繁点击,在提交成功之后再重新置为可点击态。
实现
不带参数
function debounce(fn, delay) {
//初始化定时器
let timer;
return function() {
//清除最后一次操作之前的定时器
clearTimeout(timer)
timer = setTimeout(() => {
//在延迟对应描述之后执行
fn()
}, delay)
}
}
需要考虑参数
function debounce(func, wait) {
let timer;
return function() {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(context, args);
}, wait);
};
}
需要指定作用域
前两种已经可以满足大多数需求了,但是面试官提到这种情况。
const obj = {
id: '23123',
getName: function (name){
return function() {
console.log(`id: ${this.id}, name: ${name}`);
}
}
};
let person = obj.getName('xiaoming')
let handleClick = debounce(person, 1000)
handleClick() //id: undefined, name: xiaoming
由于是在全局环境执行的所以id还是undefine,
解决方法
防抖函数中加入要绑定的对象
function debounce(func, wait, ctx) {
let timeout;
let context;
return function() {
context = ctx ? ctx : this
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args);
}, wait);
};
let person = obj.getName('xiaoming')
let handleClick = debounce(person, 1000, obj)
handleClick() //id: 23123, name: xiaoming
//直接将person绑定到obj也是可以的 但是如果在debounce里实现的话可以多传一个参数
//let person = obj.getName('xiaoming').bind(obj)
实际应用
html中
<!DOCTYPE html>
<html>
<head>
<title>防抖</title>
</head>
<body>
<h2>防抖</h2>
<button class="button">防抖</button>
</body>
<script>
function debounce(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args);
}, wait);
};
}
const button = document.querySelector('button');
button.addEventListener('click', debounce(function() {
console.log('点击了防抖')
}, 1000));
</script>
</html>
Vue中
<template>
<button @click="handleClick">防抖</button>
<template>
<script>
debounce(fn, delay) {
let timer
return function() {
clearTimeout(timer)
timer = setTimeout(() => {
fn()
}, delay)
}
},
// 这
handleClick: debounce(function() {
console.log('sf')
}, 2000)
<script>