为什么要用防抖技术
在前端开发中会遇到一些频繁的事件触发,比如:
window 的 resize、scroll
mousedown、mousemove
keyup、keydown
……
为此,我们举个示例代码来了解事件如何频繁的触发:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>频繁触发例子</title>
</head>
<body>
<input id="search" type="text" placeholder="请输入要查询的内容">
<script>
var search = document.getElementById('search');
function getUserAction() {
console.log('执行查询操作',+new Date());
};
search.addEventListener('keyup', getUserAction)
</script>
</body>
</html>
复制代码
效果图如下:
一输入内容,就会一直执行getUserAction 函数!
因为这个例子很简单,所以浏览器完全反应的过来,可是如果是复杂的回调函数或是 ajax 请求呢?假设 1 秒触发了 10 次,每个回调就必须在 1000 / 10 = 10ms 内完成,否则就会有卡顿出现。
为了解决这个问题,我们可以使用防抖
防抖原理
在事件被触发n秒后,再去执行回调函数。如果n秒内该事件被重新触发,则重新计时。结果就是将频繁触发的事件合并为一次,且在最后执行。
第一个例子
代码如下:
var search = document.getElementById('search');
function getUserAction(e) {
console.log(e);
console.log('执行查询操作',+new Date());
};
function debounce(func, wait) {
var timeout;
return args => {
if (timeout) clearTimeout(timeout)
timeout = setTimeout(func, wait);
}
}
const debounceAjax = debounce(getUserAction, 1000)
subBtn.addEventListener('keyup', debounceAjax)
复制代码
输入后1秒执行方法,一直输入以输入完为准,1秒执行方法,点击看看使用效果:
第二个例子
立刻执行
有这样一个需求,鼠标移动事件,移动到内容上,立即执行函数.
根据这段表述,我们可以写的代码:
function debounce(func, wait, immediate) {
var timeout;
return args => {
let context = this;
if (timeout) clearTimeout(timeout)
if (immediate) {
// 如果已经执行过,不在执行
let callNow = !timeout;
timeout = setTimeout(function() {
timeout = null;
},wait)
if (callNow) func.call(context, args)
} else {
timeout = setTimeout(() => {
func.call(context, args)
},wait)
}
}
}
复制代码
debounce(getUserAction, 1000, true)
鼠标移动到内容上立即执行方法,重复移动以最后一次移动为准1秒后执行方法,看看使用效果:
完善功能增加取消防抖功能
function debounce(func, wait, immediate) {
var timeout,result;
var debounced = function() {
var context = this;
var args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
// 如果已经执行过,不再执行
var callNow = !timeout;
timeout = setTimeout(function() {
timeout = null;
}, wait)
if (callNow) result = func.apply(context, args)
} else {
timeout = setTimeout(function() {
func.apply(context, args)
}, wait);
}
return result;
}
debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
}
return debounced;
}
复制代码
执行代码:
var setUseAction = debounce(getUserAction, 1000, true);
container.onmousemove = function() {
var res = setUseAction();
console.log(res)
}
document.getElementById("button").addEventListener('click', function() {
setUseAction.cancel();
})
复制代码
设置时间间隔较大10秒,当点击取消防抖后立即执行了,看看使用效果:
参考地址:
github.com/mqyqingfeng…