防抖和節流(較全&可體驗)

防抖(debounce)

概念

事件被觸發通過單位時間(delay)後再執行回調,若是在單位時間內又被觸發,則從新計時。html

防抖函數

const debounce = (cb, delay = 1000) => {
  let timer = null;
  return function (...args) {
    const context = this;
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      cb.apply(context, args);
      timer = null;
    }, delay);
  }
}

若延遲delay設置爲1000(默認值),則cb(回調函數)只會在中止觸發1s後執行,若是一直不斷地觸發,則回調函數始終不執行。app

使用

下面是一個簡單的使用示例,後續介紹的防抖和節流函數的使用方式也是類似的。dom

const callback = () => {      
  console.log(Math.random());
}
const handle = debounce(callback, 1000);
window.addEventListener('scroll', handle);

防抖函數(第一次觸發會當即執行)

const debounceImmediate = (cb, delay = 1000, immediate = true) => {
  let timer = null;
  return function (...args) {
    const context = this;
    const execNow = immediate && !timer;
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      cb.apply(context, args);
      timer = null;
    }, delay);
    execNow && cb.apply(this, args);
  }
}

當設置immediate=true(默認值)、delay=1000(默認值)時,第一次觸發會當即執行回調函數。後續執行和普通的防抖函數同樣,只有在中止觸發1s後回調函數纔會執行,若是仍是一直不斷地觸發,則回調函數始終不執行。函數

節流(throttle)

概念

規定在單位時間(delay)內,只能觸發一次函數。若是單位時間內屢次觸發函數,只會執行一次回調。this

節流函數(使用時間戳)

const throttleUseTimeStamp = (cb, delay = 1000) => {
  let startTime = Date.now();  
 return function(...args) {      
  const context = this;                        
  const now = Date.now();           
  if (now - startTime >= delay) {
      cb.apply(context, args);
      startTime = Date.now();        
  }
 } 
}

若delay=1000,則在1s內只會執行一次回調函數。spa

節流函數的實現(使用定時器)

const throttleUseTimer = (cb, delay) => {
  let timer = null;
  return function(...args) {
    const context = this;
    if (!timer) {
      timer = setTimeout(() => {
        cb.apply(context, args);      
        timer = null;      
      }, delay);  
    } 
  }
}

若delay=1000,則在1s內只會執行一次回調函數。code

節流函數的實現(第一次觸發當即執行,最後一次觸發也會執行)

const throttleExecMore = function(cb, delay) {
  let timer = null; 
  let startTime = Date.now();
  return function(...args) {        
    const curTime = Date.now(); 
    const remaining = delay - (curTime - startTime); 
    const context = this;           
    timer && clearTimeout(timer);
    if (remaining <= 0) {
      // 第一次觸發執行               
      cb.apply(context, args);              
      startTime = Date.now();         
    } else {
      // 最後一次觸發也會執行             
      timer = setTimeout(() => {
        cb.apply(context, args);
        timer = null;
      }, remaining);          
    }
  }
}

第一次觸發會當即執行回調函數,最後一次觸發也會執行一次回調函數。htm

親自體驗

將前面介紹的5種防抖和節流函數分別應用在5個輸入框的onChange事件的監聽上,delay值統一設置爲1000,快速輸入1111獲得結果以下:

徹底符合咱們前面的分析。blog

若是不加防抖、節流控制,獲得結果將是:事件

1
11
111
1111

觸發了4次回調函數。

體驗防抖和節流 (http://47.92.166.108:3000/blog/index.html#/tutorials/throttle-and-debounce)

體驗網址二維碼:

應用場景舉例

防抖

  1. 搜索聯想,在不斷輸入值時節約請求資源。
  2. 窗口resize事件

節流

  1. 鼠標不斷點擊,單位時間內只觸發一次
  2. 滾動到底部加載更多

相關文章
相關標籤/搜索