Javascript Debounce & Throttle 提升網頁效能

debounce 與 throttle 用來防止 scroll, resize 等事件處理器在短時間內被頻繁觸發,綁定的函示重複執行,造成網頁不斷重新運算進而影響效能,作法就是控制函式觸發的次數或頻率,以下分別說明兩者的操作方式。

Debounce

概念是加入一個倒數計時器,連續觸發時會一直重新倒數,直到計時器歸零,才執行函式。

簡單舉例
就像是便利商店的自動門,當一段時間內頻繁有客人進來,自動門會持續開著,直到大家都進入後,等待幾秒才關上。

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

利用閉包(closure)將 timer 變數與內部函式分享,func.apply(this, args) 可以替換成 func.call(this, ...args) 或是 func.bind(this)(...args)

如果不太清楚函數原型方法 callapplybind,以及裡面代入的 thisargument,可以參考這一篇

範例:input 輸入搜尋事件

當輸入停止超過一秒後,才去讀取輸入內容

<input type="text" placeholder="請輸入搜尋內容" id="search" />
<p id="content"></p>
const input = document.getElementById('search');
const content = document.getElementById('content');

input.addEventListener('input', debounce(updateContent));

function updateContent(e) {
content.textContent = e.target.value;
}

範例畫面:

Throttle

節流器,目的是減少事件執行的次數,事件連續觸發時製造間隔來控制運行次數。

簡單舉例
像是等紅綠燈,在固定的時間才會轉成綠燈,如果錯過了,必須等待一段時間,直到下次綠燈才能通過。

首次執行的時機:

有以下兩種,只差在首次執行,後續的結果都是一樣的。

1. 首次「立刻」執行

function throttle(func, timeout = 1000) {
let isClose = false;
let timer = null;
return function(...args) {
if (isClose) {
return;
}
func.apply(this, args); // 第一次執行不進入 settimeout() 計算
isClose = true;
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
isClose = false;
}, timeout)
}
}

2. 首次「延遲」執行

function throttle(func, timeout = 1000) {
let isClose = false;
let timer = null;
return function(...args) {
if (isClose) {
return;
}
isClose = true;
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args); // 第一次執行進入 settimeout() 計算
isClose = false;
}, timeout);
}
}

範例:scroll 視窗滾動事件

滾動視窗時,每隔一秒才執行函式,判斷是否要顯示下一區塊內容

<ul id="content"></ul>
const content = document.getElementById('content');

window.addEventListener('scroll', throttle(handleScroll));

function handleScroll() {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
content.innerHTML += '<li> ... </li>';
}
}

範例畫面:


debounce 與 throttle 適合的情境略有不同,可以藉由上述範例來觀察兩者間的差異

  1. debounce 適用在停止觸發後才執行事件(input 停止輸入後,才去讀取更新的值)
  2. throttle 適用在固定時間區間執行事件(滑鼠滾動時,每隔一秒檢查當前位置,判斷是否要撈取下一頁的資料)

參考文章:

https://medium.com/@alexian853/debounce-throttle-那些前端開發應該要知道的小事-一-76a73a8cbc39

https://ithelp.ithome.com.tw/articles/10222749

https://medium.com/@steven234/throttle跟-debounce有什麼區別-e0b1979b1b4f

CSS 製作固定比例寬高區塊(Aspect Ratio / Height Based on Width) Javascript 函數原型方法:call、apply、bind 改變 this 指向

評論

廣告
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×