Debounce & Throttle
防抖 Debounce
說明
- 事件被觸發 n 秒後,再執行動作,如果在 n 秒內再次觸發的話,就重新計時
- 單位時間內,頻繁觸發事件,只執行最後一次
- 使用
closure
保持定時器的狀態
常用情境
- 在搜尋 Input 框,輸入文字的關鍵字觸發,可以等到使用者輸入完畢再發送 API 請求
- 表單驗證,確認使用者輸入完畢再檢查格式是否通過
範例程式碼
const btn = document.querySelector('.btn')const input = document.querySelector('.input')const result = document.querySelector('.result')const pay = () => { console.log('防抖付款')}// 寫法1const debounce = (cb, delay) => { let timer return function () { // 如果在n秒內再次觸發,清除目前的定時器,重新開始計時 clearTimeout(timer) timer = setTimeout(() => { cb() }, delay) }}btn.addEventListener('click', debounce(pay, 1000))// 寫法2 : return arrow functionconst debounce2 = (cb, delay = 1500) => { let timer return (...args) => { clearTimeout(timer) timer = setTimeout(() => { // func.call(context); cb(...args) }, delay) }}const updateText = debounce2((text) => { result.textContent = text}, 1000)input.addEventListener('input', (e) => { updateText(e.target.value)})
- 在 callback function 帶入參數
function debounce(cb, delay) { let timer return (...args) => { clearTimeout(timer) timer = setTimeout(() => { cb(...args) }, delay) }}function print(str) { console.log(str)}const debouncedPrint = debounce(print, 1000)debouncedPrint('Hello, World!')
節流 Throttle
說明
- 在 n 秒內被連續觸發,也只執行一開始的那一次
- 規定一定的時間內,只能執行一次動作
- 使用
closure
保持定時器的狀態
常用情境
- 高頻率事件在每次觸發時,都會調用綁定在事件上的 callback function,造成資源浪費
- 例如滑鼠移動(mousemove)、頁面尺寸縮放(resize)、滾動條滾動(scroll)
範例程式碼
const result = document.querySelector('.result')//每隔1秒執行callback的內容function throttle(cb, time = 1000) { let timer = null return (...args) => { //如果已經在執行中,不做任何事 //直到timer被清除後,重新執行 if (timer) { return } timer = setTimeout(() => { cb(...args) timer = null }, time) }}//Infinite Scrollfunction scroll() { let clientHeight = document.documentElement.clientHeight || document.body.clientHeight let scrollTop = document.documentElement.scrollTop let scrollHeight = document.documentElement.scrollHeight //當滾動到頁面底部時... // if (scrollTop + clientHeight + 10 >= scrollHeight) { //當滾動到頁面90%時... if ((scrollTop + clientHeight) / scrollHeight >= 0.9) { for (let i = 0; i <= 10; i++) { let p = document.createElement('p') p.textContent = 'testing2...' result.appendChild(p) } }}document.addEventListener('scroll', throttle(scroll))
參考資料
# JavaScript # 效能