js如何實現防抖函數 防抖函數的3種經典實現方案

防抖函數的核心是延遲執行并重置計時,適用于搜索建議等場景。具體實現通過settimeout延遲觸發函數,若再次觸發則清除原定時器并重新計時。對于需要立即執行的情況,可引入isinvoked變量控制首次執行。同時可通過添加cancel方法實現手動取消。使用apply確保上下文和參數正確傳遞。防抖與節流的區別在于防抖保證最后一次觸發有效,而節流確保一段時間內僅執行一次。常見應用場景包括搜索建議、窗口調整、按鈕防重復點擊、文本自動保存等。

js如何實現防抖函數 防抖函數的3種經典實現方案

防抖函數的核心在于:在事件觸發后,不是立即執行,而是等待一段時間,如果在這段時間內再次觸發,就重新計時。最終只執行最后一次觸發。

js如何實現防抖函數 防抖函數的3種經典實現方案

解決方案

防抖的本質是延遲執行,并且在延遲的過程中,如果再次觸發,則重新計時。理解這一點,實現防抖就變得簡單了。

js如何實現防抖函數 防抖函數的3種經典實現方案

function debounce(func, delay) {   let timeoutId;    return function(...args) {     const context = this;      clearTimeout(timeoutId);      timeoutId = setTimeout(() => {       func.apply(context, args);     }, delay);   }; }  // 示例 function sayHello(name) {   console.log(`Hello, ${name}!`); }  const debouncedHello = debounce(sayHello, 300);  // 模擬事件觸發 debouncedHello("Alice"); debouncedHello("Bob"); setTimeout(() => debouncedHello("Charlie"), 200); // 會取消Bob的執行 setTimeout(() => debouncedHello("David"), 500); // 延遲500ms,會執行

如何使用立即執行的防抖函數?

有時候,我們希望第一次觸發事件時立即執行,而不是等待。可以修改防抖函數來實現:

js如何實現防抖函數 防抖函數的3種經典實現方案

function debounceImmediate(func, delay) {   let timeoutId;   let isInvoked = false;    return function(...args) {     const context = this;      if (!isInvoked) {       func.apply(context, args);       isInvoked = true;     }      clearTimeout(timeoutId);      timeoutId = setTimeout(() => {       isInvoked = false;     }, delay);   }; }  // 示例 function sayHelloImmediate(name) {   console.log(`Hello (Immediate), ${name}!`); }  const debouncedHelloImmediate = debounceImmediate(sayHelloImmediate, 300);  debouncedHelloImmediate("Eve"); // 立即執行 debouncedHelloImmediate("Frank"); // 不會立即執行,但會重置計時 setTimeout(() => debouncedHelloImmediate("Grace"), 500); // 延遲500ms后執行

關鍵在于引入一個isInvoked變量,控制首次是否立即執行。這種方式適用于需要立即響應的場景,例如搜索框輸入。

如何取消防抖函數的執行?

某些情況下,我們需要手動取消防抖函數的執行。可以給防抖函數添加一個cancel方法:

function debounceWithCancel(func, delay) {   let timeoutId;    function debounced(...args) {     const context = this;      clearTimeout(timeoutId);      timeoutId = setTimeout(() => {       func.apply(context, args);     }, delay);   }    debounced.cancel = () => {     clearTimeout(timeoutId);   };    return debounced; }  // 示例 function sayHelloCancelable(name) {   console.log(`Hello (Cancelable), ${name}!`); }  const debouncedHelloCancelable = debounceWithCancel(sayHelloCancelable, 300);  debouncedHelloCancelable("Henry"); setTimeout(() => debouncedHelloCancelable.cancel(), 200); // 取消執行 setTimeout(() => debouncedHelloCancelable("Ivy"), 500); // 延遲500ms,會執行

這種方式為防抖函數提供了一個額外的控制手段,可以在需要的時候阻止函數的執行。

為什么要使用apply而不是直接調用func()?

使用apply可以確保函數在正確的上下文中執行,并傳遞正確的參數。apply允許我們指定this的值(即上下文)和參數數組。這在處理事件監聽器等場景時非常重要,因為我們需要確保函數在觸發事件的元素上下文中執行。如果直接調用func(),this的值可能會指向全局對象(例如window),導致錯誤。

防抖和節流的區別是什么?

防抖和節流都是為了優化性能,減少函數執行頻率的技術,但它們的策略不同。

  • 防抖 (Debounce): 在事件被觸發后,延遲一段時間執行,如果在這段時間內事件再次被觸發,則重新計時。最終只執行最后一次觸發。適用于搜索建議、調整窗口大小等場景。
  • 節流 (Throttle): 在一段時間內,只允許函數執行一次。如果在該時間段內事件被多次觸發,只有第一次觸發會被執行。適用于滾動事件、鼠標移動等場景。

簡單來說,防抖是“最后一次有效”,節流是“一段時間內只執行一次”。

防抖函數的常見應用場景有哪些?

  • 搜索建議: 用戶在輸入框中輸入內容時,不需要每次輸入都發送請求,而是等待用戶停止輸入一段時間后,再發送請求獲取搜索建議。
  • 調整窗口大小: 在調整窗口大小的過程中,不需要每次調整都重新計算布局,而是等待調整完成后,再重新計算布局。
  • 按鈕點擊: 防止用戶快速多次點擊按鈕,導致重復提交表單或執行其他操作。
  • 文本編輯器自動保存: 用戶編輯文本時,不需要每次修改都保存,而是等待用戶停止編輯一段時間后,再自動保存。

? 版權聲明
THE END
喜歡就支持一下吧
點贊6 分享