其概念其实是从机械开关和继电器的“去弹跳”(debounce)衍生出来的,基本思路就是把多个信号合并为一个信号。在程序中防抖的作用是 只有在某个时间内没有再次触发函数时,才真正的调用这个函数,从而优化交互与性能。
以
场景1为例,减少持续输入触发的高频次请求,缓解服务器压力.
<body>
<input type="text" />
</body>
<script>
const inputEl = document.querySelector('input');
function debounce(fn, delay) {
/*
timer:定时器实例
由于闭包原理,同一条作用域链上重复调用debounce()内部的timer不会初始化,
所以能保存上一次创建的定时器实例,从而能在下一次防抖时,取消上一次请求
*/
let timer = null;
const _debounce = function() {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn();
timer = null;
}, delay);
}
return _debounce;
}
let counter = 0;
const inputChange = function() {
console.log(`发送了 ${++counter} 次网络请求`);
}
inputEl.oninput = debounce(inputChange, 1000);
/*
不使用防抖的情况下,每输入一个字符,就会触发一次请求
inputEl.oninput = inputChange;
*/
</script>
this指向和参数<body>
<input data-id="9527" type="text" />
</body>
<script>
const inputEl = document.querySelector('input');
function debounce(fn, delay) {
let timer = null;
const _debounce = function() {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
/*
回调函数中 this 指向上下文 window
inputEl.oninput 实际触发 _debounce 它的指向是 inputEl
将回调函数 this 指向到DOM对象 inputEl
回调函数将接收到输入框的事件对象 event
*/
fn.apply(this, arguments);
timer = null;
}, delay);
}
return _debounce;
}
let counter = 0;
const inputChange = function(event) {
console.log(`发送了 ${++counter} 次网络请求`);
console.log(this, event);
}
inputEl.oninput = debounce(inputChange, 1000)
</script>
<body>
<input data-id="9527" type="text" />
</body>
<script>
const inputEl = document.querySelector('input');
function debounce(fn, delay, immediate = false) {
let timer = null;
/*
是否已经执行
与 timer 同理,只会初始化一次
*/
let isInvoke = false;
const _debounce = function() {
// 首次执行并且开启了立即执行
if (immediate && !isInvoke) {
fn.apply(this, arguments);
// 标记已经执行
isInvoke = true;
} else {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
// 标记已经执行
isInvoke = true;
timer = null;
}, delay);
}
}
return _debounce;
}
let counter = 0;
const inputChange = function(event) {
console.log(`发送了 ${++counter} 次网络请求`);
console.log(this, event);
}
inputEl.oninput = debounce(inputChange, 1000, true)
</script>
<body>
<input data-id="9527" type="text" />
<button id="cancel">取消</button>
</body>
<script>
const inputEl = document.querySelector('input');
const btn = document.getElementById('cancel')
function debounce(fn, delay, immediate = false) {
let timer = null;
let isInvoke = false;
const _debounce = function() {
if (immediate && !isInvoke) {
fn.apply(this, arguments);
isInvoke = true;
} else {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
isInvoke = true;
timer = null;
}, delay);
}
}
// 取消执行的函数(清除定时器和修改isInvoke即可)
_debounce.cancel = function() {
clearTimeout(timer)
isInvoke = false;
timer = null;
}
return _debounce;
}
let counter = 0;
const inputChange = function(event) {
console.log(`发送了 ${++counter} 次网络请求`);
console.log(this, event);
}
const _debounce = debounce(inputChange, 1000, true)
// 输入框的input事件
inputEl.oninput = _debounce
// 取消按钮的点击事件
btn.onclick = function() {
_debounce.cancel()
}
</script>