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 # 效能