定义: 指触发事件后在规定时间内回调函数只能执行一次,如果在规定时间内又触发了该事件,则会重新开始算规定时,以新的事件的时间为准,n 秒后才执行
应用场景:
- 输入款搜索时,用户在不断输入值时,用防抖来节约请求资源。
- 按钮点击:比如点赞,收藏
防抖有两种实现方式:
- 非立即执行:大概步骤函数调用->延迟->执行回调函数,如果在延迟的时候又触发了函数,则重新进行延迟操作,延迟结束后执行回调函数
- 立即执行:大概步骤函数调用->执行回调函数->延迟,如果在延迟的时候又触发了函数,则重新进行延迟操作,延迟结束后不会执行回调函数
非立即执行
function debounce(fun,wait=300){
let timer = null;
return function () {
let self = this,
args = arguments;
timer && clearTimeout(timer);
timer = setTimeout(function () {
method.apply(self,args);
},delay);
}
}
复制代码
立即执行
function debounce(func,wait,immediate){
let timeout;
return function(){
let context = this;
let args = arguments;
if(timeout){
clearTimeout(timeout);
}
if(immediate){
// 如果已经执行过,不再执行
timeout = setTimeout(function(){
timeout = null;
},wait);
if (!timeout) func.apply(context, args)
}else{
timeout = setTimeout(function(){
func.apply(context,args);
},wait);
}
}
}
复制代码
扩展
假设我们传入的func是有返回值,所以我们也要返回函数的执行结果,但是当 immediate 为 false 的时候,因为使用了 setTimeout ,我们将 func.apply(context, args) 的返回值赋给变量,最后再 return 的时候,值将会一直是 undefined,所以我们只在 immediate 为 true 的时候返回函数的执行结果。
function debounce(func,wait,immediate){
let timeout,result;
return function(){
let context = this;
let args = arguments;
if(timeout){
clearTimeout(timeout);
}
if(immediate){
// 如果已经执行过,不再执行
timeout = setTimeout(function(){
timeout = null;
},wait);
if (!timeout) result = func.apply(context, args);
}else{
timeout = setTimeout(function(){
func.apply(context,args);
},wait);
}
return result;
}
}
复制代码
最后我们再思考一个小需求,我希望能取消 debounce 函数,比如说我 debounce 的时间间隔是 10 秒钟,immediate 为 true,这样的话,我只有等 8 秒或者是更长时间后才能重新触发事件,现在我希望有一个按钮,点击后,取消防抖,这样我再去触发,就可以又立刻执行啦
function debounce(func,wait,immediate){
let timeout,result;
let debounced = function(){
let context = this;
let args = arguments;
if(timeout){
clearTimeout(timeout);
}
if(immediate){
// 如果已经执行过,不再执行
timeout = setTimeout(function(){
timeout = null;
},wait);
if (!timeout) result = func.apply(context, args);
}else{
timeout = setTimeout(function(){
func.apply(context,args);
},wait);
}
return result;
}
debounced.cancel = function(){
clearTimeout(timeout);
timeout = null;
}
}
复制代码