深入理解JS函式節流和去抖動

2022-01-20 16:38:24 字數 2956 閱讀 7326

節流就是擰緊水龍頭讓水少流一點,但是不是不讓水流了。想象一下在現實生活中有時候我們需要接一桶水,接水的同時不想一直站在那等著,可能要離開一會去幹一點別的事請,讓水差不多流滿一桶水的時候再回來,這個時候,不能把水龍頭開的太大,不然還沒回來水就已經滿了,浪費了好多水,這時候就需要節流,讓自己回來的時候水差不多滿了。

那在js裡有沒有這種情況呢,典型的場景是懶載入監聽頁面的scoll事件,或者監聽滑鼠的mousemove事件,這些事件對應的處理方法相當於水,由於scroll和mousemove在滑鼠移動的時候會被瀏覽器頻繁的觸發,會導致對應的事件也會被頻繁的觸發(水流的太快了),這樣就會造成很大的瀏覽器資源開銷,而且好多中間的處理是不必要的,這樣就會造成瀏覽器卡頓的現象,這時候就需要節流。

如何節流呢?我們無法做到讓瀏覽器不去觸發對應的事件,但是可以做到讓處理事件的方法執行頻率減少,從而減少對應的處理開銷

最早接觸這個詞應該是在高中物理裡面學到的,有時候開關在在真正閉合之前可能會發生一些抖動現象,如果抖動的明顯的話,對應的小燈泡可能會閃爍,把燈泡閃壞了不重要,萬一把眼睛再給閃壞了可就麻煩了,這個時候就有去抖電路的出現。

而在我們的頁面裡,也有這種情況,假設我們的乙個輸入框,輸入內容的同時可能會去後台查詢對應的聯想詞,如果使用者輸入的同時,頻繁的觸發input事件,然後頻繁的向後台傳送請求,那麼直到使用者輸入完成時,之前的請求都應該是多餘的,假設網路慢一點,後台返回的資料比較慢,那麼顯示的聯想詞可能會出現頻繁的變換,直到最後的乙個請求返回。

如何去抖呢?這個時候就可以在一定時間內監聽是否再次輸入,如果沒有再次輸入則認為本次輸入完成,傳送請求,否則就是判定使用者仍在輸入,不傳送請求。

去抖和節流是不同的,因為節流雖然中間的處理函式被限制了,但是只是減少了頻率,而去抖則把中間的處理函式全部過濾掉了,只執行規判定時間內的最後乙個事件

/*

* 實現思路:

** 引數需要乙個執行的頻率,和乙個對應的處理函式,

** 內部需要乙個lasttime 變數記錄上一次執行的時間

**/function throttle(func, wait)

}}

再看如何呼叫:

//

由於閉包的存在,呼叫會不一樣

let throttlerun = throttle(() =>,

400);

window.addeventlistener(

'scroll

', throttlerun);

這時候瘋狂的滾動頁面,會發現會400ms列印乙個123,而沒有節流的話會不斷地列印, 你可以改變wait引數去感受下不同。

但是到這裡,我們的節流方法是不完善的,因為我們的方法沒有獲取事件發生時的this物件,而且由於我們的方法簡單粗暴的通過判斷這次觸發的時間和上次執行時間的間隔來決定是否執行**,這樣就會造成最後一次觸發無法執行,或者使用者出發的間隔確實很短,也無法執行,造成了誤殺,所以需要對方法進行完善。

function throttle(func, wait) 

lasttime =now;

} else

if (!timeout) , wait);}};

}

這樣我們的方法就相對完善了,呼叫方法和之前相同。

去抖的方法,和節流思路一致,但是只有在抖動被判定結束後,方法才會得到執行。

function debounce(func, wait) , wait);

} else

timeout = settimeout(() =>, wait);

}//注意這裡lasttime是上次的觸發時間

lasttime =now;

}}

這時候按照之前同樣的方式呼叫,會發現無論怎麼瘋狂的滾動視窗,只有停止滾動時,才會執行對應的事件。

去抖和節流已經有很多成熟的js進行了實現,其大致思路基本是這樣的。

方法一:

這種實現方式的思路很好理解:設定乙個一間隔時間,比如50毫秒,以此時間為基準設定定時器,當第一次觸發事件到第二次觸發事件間隔小於50毫秒時,清除這個定時器,並設定乙個新的定時器,以此類推,直到有一次事件觸發後50毫秒內沒有重複觸發。

**如下:

function debounce(method) , 

50);

}

這種設計方式有乙個問題:本來應該多次觸發的事件,可能最終只會發生一次。具體來說,乙個循序漸進的滾動事件,如果使用者滾動太快速,或者程式設定的函式節流間隔時間太長,那麼最終滾動事件會呈現為乙個很突然的跳躍事件,中間過程都被節流截掉了。這個例子舉的有點誇張了,不過使用這種方式進行節流最終是會明顯感受到程式比不節流的時候「更突兀」,這對於使用者體驗是很差的。有一種彌補這種缺陷的設計思路。

方法二:

第二種實現方式的思路與第一種稍有差別:設定乙個間隔時間,比如50毫秒,以此時間為基準穩定分隔事件觸發情況,也就是說100毫秒內連續觸發多次事件,也只會按照50毫秒一次穩定分隔執行。**如下:

var oldtime = new

date().gettime();

var delay = 50

;function throttle1(method)

}

相比於第一種方法,第二種方法也許會比第一種方法執行更多次(有時候意味著更多次請求後台,即更多的流量),但是卻很好的解決了第一種方法清除中間過程的缺陷。因此在具體場景應根據情況擇優決定使用哪種方法。

對於方法二,我們再提供另一種同樣功能的寫法:

var timer =undefined,

delay = 50

;function throttle2(method)

method();

timer =settimeout(function() , delay);

}

前端效能篇 函式節流和去抖動

我們前端在開發過程經常用到 scroll resize等高頻的事件,特別在監測瀏覽器變化以及在下拉載入大資料的過程中,當這些高頻的事件發生時,這些高頻的事件觸發的頻次非常高,也非常大的多,間隔的時間也很短。如果這些高頻的事件中要及到大量的位置計算 dom 操作 ui重繪等等業務,但是偏偏業務計算和操...

js 函式節流 與 防抖動

函式節流 就如同成都搖號買房,前乙個進去選房了,下乙個就要等一段時間。這種策略就很好的解決了,一大波人進去選房,銷售妹妹沒發接待的尷尬局面。應用場景 監聽瀏覽器滾動條,然後觸發函式。普通做法 document.getelementbyid throttle onscroll function 函式節...

JS 函式節流和去抖

1 什麼是節流和去抖?節流。就是擰緊水龍頭讓水少流一點,但是不是不讓水流了。想象一下在現實生活中有時候我們需要接一桶水,接水的同時不想一直站在那等著,可能要離開一會去幹一點別的事請,讓水差不多流滿一桶水的時候再回來,這個時候,不能把水龍頭開的太大,不然還沒回來水就已經滿了,浪費了好多水,這時候就需要...