深入理解前端防抖(Debounce)與節(jié)流(Throttle):原理、區(qū)別與實(shí)戰(zhàn)示例

在前端開發(fā)中,我們經(jīng)常需要處理高頻事件(如輸入框輸入、滾動(dòng)、窗口調(diào)整大小等)。如果不加限制,瀏覽器會(huì)頻繁觸發(fā)回調(diào)函數(shù),導(dǎo)致性能問題,甚至頁面卡頓。

防抖(Debounce) 和 節(jié)流(Throttle) 是兩種優(yōu)化方案,可以有效控制事件觸發(fā)的頻率,提高應(yīng)用的性能和用戶體驗(yàn)。

本篇文章將詳細(xì)解析 防抖和節(jié)流的原理、適用場景及代碼實(shí)現(xiàn),幫助你更好地優(yōu)化前端應(yīng)用。

1. 什么是防抖(Debounce)?

防抖是一種在事件觸發(fā)后延遲執(zhí)行的技術(shù),如果在延遲期間事件被再次觸發(fā),計(jì)時(shí)器會(huì)重置,重新計(jì)算延遲時(shí)間。

核心思想:短時(shí)間內(nèi)多次觸發(fā),只執(zhí)行最后一次。

適用場景

搜索框輸入(防止用戶每次輸入都發(fā)送請求)
窗口調(diào)整大小(resize)(防止短時(shí)間內(nèi)多次觸發(fā)計(jì)算)
表單輸入驗(yàn)證(用戶停止輸入后再進(jìn)行驗(yàn)證)

function debounce(fn, delay = 300) {
    let timer;
    return function (...args) {
        if (timer) clearTimeout(timer); // 清除之前的定時(shí)器
        timer = setTimeout(() => fn.apply(this, args), delay);
    };
}

示例:輸入框防抖
<input type="text" id="search" placeholder="請輸入內(nèi)容">
<script>
const input = document.getElementById('search');

input.addEventListener('input', debounce((e) => {
    console.log('搜索內(nèi)容:', e.target.value);
}, 500));
</script>

效果:用戶輸入停止 500ms 后,才觸發(fā) console.log。

2. 什么是節(jié)流(Throttle)?

節(jié)流是一種限定函數(shù)執(zhí)行頻率的技術(shù),即在一定時(shí)間間隔內(nèi),函數(shù)最多執(zhí)行一次,即使事件被頻繁觸發(fā)。

核心思想:高頻觸發(fā),固定間隔執(zhí)行。

適用場景
滾動(dòng)事件(scroll)(如懶加載、頁面滾動(dòng)監(jiān)聽)
鼠標(biāo)移動(dòng)(mousemove)(防止觸發(fā)過多計(jì)算)
按鈕點(diǎn)擊(click)(防止用戶瘋狂點(diǎn)擊)
代碼實(shí)現(xiàn)

function throttle(fn, interval = 300) {
    let lastTime = 0;
    return function (...args) {
        const now = Date.now();
        if (now - lastTime >= interval) {
            fn.apply(this, args);
            lastTime = now;
        }
    };
}

示例:滾動(dòng)監(jiān)聽
<div style="height: 2000px;"></div>
<script>
window.addEventListener('scroll', throttle(() => {
    console.log('滾動(dòng)中...', new Date().toLocaleTimeString());
}, 1000));
</script>
效果:無論滾動(dòng)多快,scroll 事件每秒最多執(zhí)行一次。

3. 防抖 vs. 節(jié)流:有什么區(qū)別?

防抖(Debounce)

觸發(fā)方式:事件觸發(fā)后延遲執(zhí)行
特性:短時(shí)間連續(xù)觸發(fā),只執(zhí)行最后一次
適用場景:輸入框輸入、搜索框、表單驗(yàn)證
優(yōu)勢:避免無效調(diào)用,減少資源消耗
實(shí)現(xiàn)方式:setTimeout 延遲執(zhí)行

節(jié)流(Throttle)

觸發(fā)方式:事件觸發(fā)后間隔執(zhí)行
特性:固定時(shí)間間隔內(nèi)最多執(zhí)行一次
適用場景:滾動(dòng)、鼠標(biāo)移動(dòng)、按鈕點(diǎn)擊
優(yōu)勢:保證高頻事件可執(zhí)行,提高流暢度
實(shí)現(xiàn)方式:Date.now() 控制執(zhí)行間隔

總結(jié)

如果你想等用戶停止操作后再執(zhí)行任務(wù),使用防抖(Debounce)。
如果你希望控制函數(shù)執(zhí)行的頻率,使用節(jié)流(Throttle)。

4. 進(jìn)階優(yōu)化:使用 Lodash

我們可以直接使用 Lodash 提供的 debounce 和 throttle 方法,避免自己實(shí)現(xiàn)。

npm install lodash

 Lodash 防抖
import _ from 'lodash';

const handleInput = _.debounce((e) => {
    console.log('防抖觸發(fā):', e.target.value);
}, 500);

document.getElementById('search').addEventListener('input', handleInput);

Lodash 節(jié)流
const handleScroll = _.throttle(() => {
    console.log('節(jié)流觸發(fā)', new Date().toLocaleTimeString());
}, 1000);

window.addEventListener('scroll', handleScroll);

Lodash 優(yōu)勢:內(nèi)部優(yōu)化更好,支持立即執(zhí)行(leading)和延遲執(zhí)行(trailing)。

結(jié)合 Vue 實(shí)戰(zhàn)應(yīng)用

//Vue 中使用防抖
<template>
  <input v-model="searchText" @input="handleInput" placeholder="搜索">
</template>

<script>
import { ref } from 'vue';
import _ from 'lodash';

export default {
  setup() {
    const searchText = ref('');

    const handleInput = _.debounce((e) => {
      console.log('搜索關(guān)鍵詞:', e.target.value);
    }, 500);

    return { searchText, handleInput };
  },
};
</script>
//效果:用戶停止輸入 500ms 后才會(huì)觸發(fā)搜索請求。


//Vue 中使用節(jié)流
<template>
  <button @click="handleClick">點(diǎn)擊節(jié)流</button>
</template>

<script>
import _ from 'lodash';

export default {
  setup() {
    const handleClick = _.throttle(() => {
      console.log('按鈕點(diǎn)擊', new Date().toLocaleTimeString());
    }, 2000);

    return { handleClick };
  },
};
</script>
//效果:按鈕每 2s 只能點(diǎn)擊一次。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容