魯斯前端布魯斯前端

文章中英模式

布魯斯前端JS面試題目 - 實作節流函數優化數據請求

學習如何實作節流函數,控制高頻事件觸發頻率,優化滾動加載、頻繁API請求等前端性能問題。

影片縮圖

懶得看文章?那就來看影片吧

什麼是節流 (Throttle)?

節流是一種優化技術,用於限制函數在一段時間內的執行頻率。與防抖(Debounce)僅執行最後一次操作不同,節流確保函數在指定的時間間隔內最多執行一次。

核心原理:固定間隔時間內只執行一次函數,無論事件觸發頻率多高,效果類似於水龍頭的流量控制。

節流應用場景

  • 1. 滾動事件處理(如滾動加載、固定導航欄)
  • 2. 監聽resize事件調整佈局
  • 3. 拖拽操作更新介面
  • 4. 頻繁的資料請求或API呼叫
  • 5. 實時遊戲中的按鍵響應
  • 6. Canvas 繪圖操作

基本實作:節流函數 (Throttle)

以下是兩種常見的實現方式:時間戳方法和定時器方法。

方法一:時間戳實現

function throttle(func, delay = 300) {
  let lastTime = 0;
  
  return function(...args) {
    const now = Date.now();
    
    // 檢查距離上次執行是否已經超過延遲時間
    if (now - lastTime >= delay) {
      func.apply(this, args);
      lastTime = now;
    }
  };
}

方法二:定時器實現

function throttle(func, delay = 300) {
  let timer = null;
  
  return function(...args) {
    // 如果沒有定時器運行中,則設置新的定時器
    if (!timer) {
      timer = setTimeout(() => {
        func.apply(this, args);
        timer = null;
      }, delay);
    }
  };
}

方法三:綜合方法(首尾調用都不丟失)

function throttle(func, delay = 300) {
  let timer = null;
  let lastTime = 0;
  
  return function(...args) {
    const now = Date.now();
    const remaining = delay - (now - lastTime);
    
    // 清除定時器並立即執行
    if (remaining <= 0) {
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
      
      func.apply(this, args);
      lastTime = now;
    } else if (!timer) {
      // 設置定時器,確保最後一次操作被執行
      timer = setTimeout(() => {
        func.apply(this, args);
        lastTime = Date.now();
        timer = null;
      }, remaining);
    }
  };
}

實際應用:節流優化資料請求

以下是一些節流函數在資料請求中的實際應用:

案例一:滾動加載資料

// 頁面滾動時加載更多數據
function loadMoreData() {
  console.log('加載更多數據...');
  
  // 計算滾動位置
  const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
  const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
  const clientHeight = document.documentElement.clientHeight || window.innerHeight;
  
  // 滾動到底部附近時,加載更多
  if (scrollTop + clientHeight >= scrollHeight - 100) {
    fetch('/api/posts?page=' + currentPage)
      .then(response => response.json())
      .then(data => {
        // 處理數據,添加到頁面上
        displayData(data);
        currentPage++;
      });
  }
}

// 使用節流函數優化滾動事件
const throttledLoadMore = throttle(loadMoreData, 500);

window.addEventListener('scroll', throttledLoadMore);

案例二:即時搜尋建議

// 發送搜尋請求
function fetchSearchResults(query) {
  console.log('搜尋:', query);
  
  fetch(`/api/search?q=${encodeURIComponent(query)}`)
    .then(response => response.json())
    .then(results => {
      // 更新搜尋結果顯示
      updateSearchResults(results);
    })
    .catch(error => {
      console.error('搜尋錯誤:', error);
    });
}

// 使用節流函數限制請求頻率
const throttledSearch = throttle(fetchSearchResults, 300);

// 綁定到輸入事件
document.querySelector('#search-input').addEventListener('input', (e) => {
  const query = e.target.value.trim();
  if (query.length > 2) {
    throttledSearch(query);
  }
});

節流與防抖比較

節流和防抖都是限制事件處理頻率的方法,但適用於不同場景:

特性節流 (Throttle)防抖 (Debounce)
執行時機固定時間內最多執行一次等待指定時間後執行,期間若再觸發則重新計時
執行頻率穩定固定的頻率僅在事件停止後執行一次
適用場景滾動加載、拖拽效果、頻繁API呼叫搜尋建議、表單驗證、視窗調整大小
類比水龍頭限流電梯等待所有人進入後再啟動