Post

去抖 Debounce & 節流 Throttle 優化前端效能

在現代前端開發中,Debounce 和 Throttle 是兩個常見的技術,用於控制高頻率事件的觸發次數。這些技術能夠幫助優化效能,提升應用的響應速度和用戶體驗。本篇文章將介紹 Debounce 和 Throttle 的概念、區別以及如何在 Vue 3 中使用這些技術。

去抖 Debounce

Debounce 的概念是將高頻率觸發的事件(如輸入框輸入事件)進行延遲處理,只有在事件停止觸發一段時間後才執行相應的函數。這樣可以防止多次重複執行相同的操作

原理

兩秒後在執行,兩秒內有人又來,就再延後

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function debounce(func, delay) {
  let timer = null;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func(...args);    // 等過 delay 才真正執行
    }, delay);
  }
}

const debouncedFunction = debounce(function(e) {
  console.log(e.target.value);
}, 2000);

document.querySelector('input').addEventListener('input', debouncedFunction);

使用場景

  • 按鈕提交:防止多次提交按鈕,只執行最後一次提交
  • 伺服器驗證:表單驗證需要伺服器端配合時,只執行連續輸入事件的最後一次,例如即時搜尋、Email 是否被註冊過

範例

不需要重複造輪,可以直接使用 lodash-es,是使用 lodash-es 不是 lodash 哦,lodash-es 利用 tree shaking 技術來減少最終打包文件的大小

1
npm install --save lodash-es
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
  <div>
    <input type="text" v-on:input="handleInput" />
    <p>搜尋結果:</p>
  </div>
</template>

<script setup>
import { debounce } from 'lodash-es';
import { ref } from 'vue';

const input = ref('');
const searchResult = ref('');

async function fetchSearchResult(query) {
  // 模擬 API 請求
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(`搜尋結果為:${query}`);
    }, 500);
  });
};

const handleInput = debounce(async (event) => {
  input.value = event.target.value;
  searchResult.value = await fetchSearchResult(input.value);
}, 2000);
</script>

節流 Throttle

Throttle 的概念是將高頻率觸發的事件進行節流處理,在一定的時間間隔內只執行一次函數。這樣可以確保在特定時間內,事件處理函數最多只會被調用一次

原理

與 Debounce 的程式邏輯相似,只多了一個時間間隔的判斷 (例如:兩秒內只有一次)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function throttle(func, delay) {
  let inThrottle = false;
  return function(...args) {
    if (!inThrottle) {  // 正在執行,就跳過
      func(...args);
      inThrottle = true;
      setTimeout(() => {
        inThrottle = false; // delay 後才釋放 inThrottle,讓後面的人可以再執行
      }, delay);
    }
  }
}

const throttledFunction = throttle(function(e) {
  console.log(e.target.value);
}, 2000);

document.querySelector('input').addEventListener('input', throttledFunction);

使用場景

  • 拖曳:固定時間內只執行一次,防止超高頻次觸動位置變動
  • 縮放:監控瀏覽器 resize
  • 動畫:避免短時間內多次觸發動畫引發效能問題

範例

這裡也是直接使用 lodash-es

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
  <div>
    <div v-on:scroll="handleScroll" style="height: 200px; overflow-y: scroll;">
      <div style="height: 1000px;">Scroll me</div>
    </div>
    <p>滾動位置:</p>
  </div>
</template>

<script setup>
import { throttle } from 'lodash-es';
import { ref } from 'vue';

const scrollPosition = ref(0);

const handleScroll = throttle((event) => {
  scrollPosition.value = event.target.scrollTop;
}, 2000);
</script>

總結

Debounce 和 Throttle 是兩個強大的工具,可以幫助控制高頻事件的觸發,從而優化效能。Debounce 適用於需要在事件停止後執行的場景,而 Throttle 適用於需要在固定時間間隔內執行的場景。在實際運用中,我們可以使用 lodash 庫輕鬆實現這些功能,提升應用的用戶體驗和效能。

參考資料

This post is licensed under CC BY 4.0 by the author.