防抖與節流
- 文章發表於
前言
想像一下,當你在某個網站透過搜尋框尋找東西時,你輸入的每一個字都會立即觸發一次自動推薦(auto suggest)的 API,這樣的使用體驗可能會讓使用者直接離開,轉向競品。
雖然功能看似簡單,但如果沒有妥善處理,可能會造成一連串的問題:
- 伺服器過載:過於頻繁的 API 請求會對伺服器造成巨大的負擔。如果後端沒有做流量控管,甚至可能導致伺服器崩潰。
- 競態條件(Race Condition):例如,你先輸入「apple is」,接著立刻改成「banana」,由於請求回應的時間差,畫面上可能同時有機會出現「apple is」或「banana」的推薦結果。
- 介面卡頓:當每輸入一個字就立即更新結果,畫面會不停地在「載入中」與「顯示結果」之間閃爍切換,造成突兀且不舒服的使用體驗。
這篇文章將會介紹兩種常見的解決方案,來解決類似的問題:防抖(Debounce)和節流(Throttle)。
節流
什麼是節流?
節流是一種讓函式執行「平均分布在時間軸上」的技巧,無論觸發事件的頻率有多高,節流確保函式在指定的間隔內最多被呼叫一次,例如設定每秒執行一次,那即使事件連續被觸發 100 次,也只會每秒處理一次,節奏是固定的。
核心原理
- 第一次函式呼叫時立即執行
- 設定一個冷卻期(cooling period)
- 在冷卻期內,忽略或記錄新的函式呼叫
- (選用) 冷卻期結束後,可以再次執行上一個函式
使用場景
節流適合用在「需要穩定執行頻率」的情境,例如:
- 捲動事件:限制捲動事件處理頻率
- 視窗調整大小:限制調整大小時的重新計算
- 滑鼠移動:限制滑鼠移動事件處理頻率
- 遊戲控制:限制按鍵事件處理頻率
- 拖曳和繪圖操作:確保平滑的視覺效果
Throttle 的實作
這個基本實作在大多數簡單場景中已經足夠,比如限制按鈕點擊或基本的滾動事件處理。
function throttle(func, wait) {let shouldThrottle = false;return function (...args) {if (shouldThrottle) return;shouldThrottle = true;func.apply(this, args);setTimeout(() => {shouldThrottle = false;}, wait);};}
防抖
什麼是防抖?
防抖是另一種控制函式執行頻率的技術,它保證函式在指定時間「最後一次」觸發後才執行一次。簡單來說,只有在一段時間內沒有新的觸發時,才真正執行函式;節流則是讓函式以固定頻率執行,即使中間有很多觸發,也只會定期處理一次。
核心原理
- 第一次觸發時,設定一個冷卻期(cooling period)
- 在冷卻期內,若有新的觸發,就取消上一次的計時器並重置冷卻期
- 冷卻期結束後,執行函式,並且清除計時器
使用場景
防抖特別適合用在「等待使用者停下來再做事」的情境,換句話說就是,它最適合應對那種短時間內會被大量觸發的事件,但我們其實只在意「最後一次」的狀況。
- 搜尋建議:使用者暫停輸入後才發起搜尋請求。
- 表單驗證:輸入框停止輸入後才觸發驗證。
- 自動儲存:使用者停止編輯一段時間後才自動儲存。
防抖的實作
function debounce(func, wait) {let timeId = null;return function (...args) {if (timeId) {clearTimeout(timeId);}timeId = setTimeout(() => {func.apply(this, args);}, wait);};}
節流 & 防抖比較
如果您喜歡這篇文章,請點擊下方按鈕分享給更多人,這將是對筆者創作的最大支持和鼓勵。