>防抖與節流是前端性能優化中很重要的一環,防抖可以用來減少頁面請求數量,節流則可以用于減少監聽事件回調函數的觸發次數。
防抖與節流都是用來減少頁面開銷的方法,在我們常用的loadsh庫中就提供了這些方法,本章主要講述防抖與節流的理念,讓我們在知其然的情況下更知其所以然。
<br />
### 防抖概念
一般用于用戶在一定時間內不觸發特定動作時再觸發回調函數。主要適用于搜索框的情況,拼音輸入法存在一個問題在于每鍵入一個字母就會去搜索一次,但是這時候往往用戶是沒有完成輸入的,在這種情況下可以通過防抖的方法來解決這個問題,在一定時間內用戶沒有重新觸發特定的動作再去觸發這個動作對應的回調函數。
舉個??:
在淘寶上和賣家產生糾紛時,找淘寶人工客服,一般問題解決后會結束會話,但是在忘記結束會話的情況下,在一定時間內我們沒有給客服回復時會自動結束會話,但如果我們在這個時間段內隨便說一個字,這個時間就會重新計時,這和防抖機制是相似的。
代碼來說話
```javascript
function debounce (fn, timeout) {
// 添加定時器變量
let timer = null;
return function () {
// 保留this
let that = this;
// 記錄參數
let args = arguments;
// 獲取當前時間,并將其轉化為時間戳
let now = +new Date();
// 如果存在定時器,清除上一個定時器
if (timer) {
clearTimeout(timer);
}
// 設定新的定時器
setTimeout(() => {
fn.apply(that, args);
last = now;
}, timeout)
}
}
const clickTarget = document.getElementById('btn');
clickTarget.addEventListener('click', debounce(() => {
console.log('2s內無操作,觸發防抖事件');
}, 2000))
```
<br />
### 節流概念
節流一般用與懶加載的情況下,懶加載需要實時監控頁面滾動距離以及元素是否顯示在所見的文檔流當中,但有時候用戶會頻繁的上下滾動但不會觸發修改src事件,這會導致頁面性能很低,因此會做節流處理。
舉個??:
在游樂場玩的時候,我們需要排隊,就算沒有人來的項目也是按時開啟的,只要到了項目開始的時間,就立馬開始不會等待。后續的任務都要留在下一次執行。
代碼說話
```javascript
function throttle(fn, delay) {
let time = 0;
return function () {
let now = +new Date();
let that = this;
if (now - time >= delay) {
time = now;
fn.apply(that, arguments);
}
}
}
const clickTarget = document.getElementById('btn');
clickTarget.addEventListener('click', throttle(() => {
console.log('時間到達2s,觸發節流事件');
}, 2000))
```
<br />
### 實際使用
在實際使用中,我們會將防抖和節流結合起來使用,如果單純的使用防抖的話只要中間有變動任務就會無限制的延期,這并不是我們想要的。
還是拿游樂場來舉個??:
游樂場現在有個項目,在排隊過程中,只要有人來就要記錄當前來人的時間,如果在之后的兩分鐘內沒有新的游客來排隊,就直接開始游戲,但如果只是這個規格會存在一個問題,如果后續一直來人游戲就無法開始,因此有了另一個規則,只要距離上一次游戲結束20分鐘后就必須開啟新的游戲,而不管后續有沒有人來,這樣會保證排隊的游客不會等待太長的時間。
代碼說話
```javascript
function dethrottle (fn, timeout, interval) {
let timer = null;
let last = 0;
return function() {
let that = this;
let args = arguments;
let now = +new Date();
// 超過最長時間限制后就強制執行,并清除定時器
if (now - last > interval) {
timer ? cleartTimeout(timer) : null;
last = now;
fn.apply(that, args);
} else {//不超過就重新設置定時器
timer = setTimeout(() => {
fn.apply(that, args);
}, timeout)
}
}
}
```