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('防抖付款')
}
// 寫法1
const debounce = (cb, delay) => {
let timer
return function () {
// 如果在n秒內再次觸發,清除目前的定時器,重新開始計時
clearTimeout(timer)
timer = setTimeout(() => {
cb()
}, delay)
}
}
btn.addEventListener('click', debounce(pay, 1000))
// 寫法2 : return arrow function
const 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 Scroll
function 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 # 效能