定義: 指觸發事件後在規定時間內回撥函式只能執行一次,如果在規定時間內又觸發了該事件,則會重新開始算規定時,以新的事件的時間為準,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;
}
}
複製程式碼