JavaScript 前端效能優化之事件防抖

mst發表於2019-04-12

JavaScript 前端效能優化之事件防抖

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

相關文章