1. 程式人生 > 其它 >瞭解防抖debounce函式與節流throttle函式

瞭解防抖debounce函式與節流throttle函式

技術標籤:JavaScirpt

文章目錄

作用

  • 優化高頻率執行js程式碼的一種手段,js中的一些事件如瀏覽器的resize、scroll,滑鼠的mousemove、mouseover,input輸入框的keypress等事件在觸發時,會不斷地呼叫繫結在事件上的回撥函式,極大地浪費資源,降低前端效能。
  • 為了優化體驗,需要對這類事件進行呼叫次數的限制

防抖函式

在事件被觸發n秒後再執行回撥,如果在這n秒內又被觸發,則重新計時。

對於函式防抖,有以下幾種應用場景:

  • 給按鈕加函式防抖防止表單多次提交。
  • 對於輸入框連續輸入進行AJAX驗證時,用函式防抖能有效減少請求次數。
  • 判斷scroll是否滑到底部,滾動事件+函式防抖

總的來說,適合多次事件一次響應的情況

  • 首先我們寫一個監聽滑鼠移動事件:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title
>
</head> <body> <script> function testDebounce() { console.log('test'); } document.onmousemove = () => { testDebounce(); } </script> </body> </html>

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-MCQvkJaf-1613098911872)(/Users/mac/Desktop/前端學習筆記/Javascript/JS高階/防抖函式與節流函式/1.gif)]

  • 最簡單的防抖函式:
var timer; // 維護同一個timer
function debounce(fn, delay) {
    clearTimeout
(timer); timer = setTimeout(function(){ fn(); }, delay); }
  • 為滑鼠移動事件新增防抖函式:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    var timer; // 維護同一個timer
    function debounce(fn, delay) {
        clearTimeout(timer);
        timer = setTimeout(function(){
            fn();
        }, delay);
    }
    // test
    function testDebounce() {
        console.log('test');
    }
    document.onmousemove = () => {
      // testDebounce();
      debounce(testDebounce, 1000);
    }
  </script>
</body>
</html>

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-YhIeNb8m-1613098911875)(/Users/mac/Desktop/前端學習筆記/Javascript/JS高階/防抖函式與節流函式/2.gif)]

  • 上面例子中的debounce就是防抖函式,在document中滑鼠移動的時候,會在onmousemove最後觸發的1s後執行回撥函式testDebounce;如果我們一直在瀏覽器中移動滑鼠(比如10s),會發現會在10 + 1s後才會執行testDebounce函式(因為clearTimeout(timer)),這個就是函式防抖。

  • 可以看到大大減小了onmousemove事件的呼叫次數。

  • 防抖函式優化進階:

function debounce(fn, delay) {
  let timer = null;
  return function(...args) {
    if(timer) clearTimeout(timer);
    timer = setTimeout(() => {
  	  fn.apply(this, args);
    }, delay);
  }
}
  • 進階測試:
function debounce(fn, delay) {
  let timer = null;
  return function(...args) {
    if(timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  }
}
// test
function testDebounce(e, content) {
  console.log(e, content);
}
var testDebounceFn = debounce(testDebounce, 1000); // 防抖函式
document.onmousemove = function (e) {
  testDebounceFn(e, 'debounce'); // 給防抖函式傳參
}

節流函式

每隔一段時間,只執行一次函式。

對於函式節流,有如下幾個場景:

  • 遊戲中的重新整理率
  • DOM元素拖拽
  • Canvas畫筆功能

總的來說,適合大量事件按時間做平均分配觸發。

  • 節流函式
function throttle(fn, gapTime) {
  let _lastTime = null;
  return function () {
    let _nowTime = + new Date()
    if (_nowTime - _lastTime > gapTime || !_lastTime) {
      fn();
      _lastTime = _nowTime
    }
  }
}
  • 測試:
let fn = ()=>{
console.log('boom')
}

setInterval(throttle(fn,1000),10)

結果是一秒打出一次boom

比較

相同點:

  • 都可以通過使用 setTimeout 實現。
  • 目的都是,降低迴調執行頻率。節省計算資源。

不同點:

  • 函式防抖,在一段連續操作結束後,處理回撥,利用clearTimeout 和 setTimeout實現。函式節流,在一段連續操作中,每一段時間只執行一次,頻率較高的事件中使用來提高效能。
  • 函式防抖關注一定時間連續觸發的事件只在最後執行一次,而函式節流側重於一段時間內只執行一次。