JavaScript函數(shù)防抖示例詳解
前言
函數(shù)防抖(Debounce)是JavaScript中一種常用的性能優(yōu)化技術(shù),主要用于控制函數(shù)執(zhí)行的頻率。
什么是函數(shù)防抖?
函數(shù)防抖是指在一定時間間隔內(nèi),如果事件被連續(xù)觸發(fā),則只執(zhí)行最后一次觸發(fā)的事件處理函數(shù)。簡單來說,就是讓一個函數(shù)在一定時間內(nèi)只執(zhí)行一次。
實現(xiàn)原理
函數(shù)防抖的核心原理是使用定時器(setTimeout)來延遲函數(shù)的執(zhí)行:
- 當(dāng)事件觸發(fā)時,清除之前的定時器
- 設(shè)置一個新的定時器
- 如果在定時器到期前事件再次被觸發(fā),則重復(fù)上述過程
- 只有當(dāng)事件停止觸發(fā)一段時間后,函數(shù)才會真正執(zhí)行
應(yīng)用場景
- 搜索框輸入聯(lián)想(避免每次輸入都發(fā)送請求)
- 窗口大小調(diào)整事件
- 滾動事件處理
- 表單驗證(在用戶停止輸入后進行驗證)
基礎(chǔ)實現(xiàn)
function debounce(func, delay) {
let timer = null;
return function() {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(context, args);
}, delay);
};
}
這是一個基本的防抖函數(shù)實現(xiàn),接收要執(zhí)行的函數(shù)和延遲時間作為參數(shù)。
進階實現(xiàn)(立即執(zhí)行版本)
debounce(func, delay, immediate) {
let timer = null;
return function() {
const context = this;
const args = arguments;
if (timer) clearTimeout(timer);
if (immediate) {
const callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, delay);
if (callNow) func.apply(context, args);
} else {
timer = setTimeout(() => {
func.apply(context, args);
}, delay);
}
};
}
這個版本增加了立即執(zhí)行選項,第一次觸發(fā)會立即執(zhí)行函數(shù)。
使用示例
// 搜索框輸入防抖
const searchInput = document.getElementById('search');
const searchHandler = debounce(function() {
console.log('搜索:', this.value);
// 這里可以添加實際的搜索邏輯
}, 500);
searchInput.addEventListener('input', searchHandler);
// 窗口大小調(diào)整防抖
const resizeHandler = debounce(function() {
console.log('窗口大小已調(diào)整');
}, 200);
window.addEventListener('resize', resizeHandler);
注意事項
- 防抖時間間隔需要根據(jù)實際場景合理設(shè)置
- 對于需要立即反饋的操作(如按鈕點擊),不適合使用防抖
- 防抖函數(shù)會延遲執(zhí)行,可能導(dǎo)致用戶體驗上的延遲感
函數(shù)防抖是前端性能優(yōu)化的重要手段,合理使用可以顯著提升頁面性能。

函數(shù)防抖和函數(shù)節(jié)流有什么區(qū)別?
函數(shù)防抖(Debounce)和函數(shù)節(jié)流(Throttle)是前端開發(fā)中兩種常用的性能優(yōu)化技術(shù),用于控制高頻觸發(fā)事件的執(zhí)行頻率。雖然兩者都旨在減少函數(shù)執(zhí)行次數(shù),但它們的實現(xiàn)邏輯和適用場景有顯著區(qū)別。以下是兩者的詳細對比與分析:
一、核心區(qū)別對比
| 維度 | 函數(shù)防抖(Debounce) | 函數(shù)節(jié)流(Throttle) |
|---|---|---|
| 核心邏輯 | 延遲執(zhí)行:事件觸發(fā)后等待一段時間,若期間無新觸發(fā)則執(zhí)行;若有新觸發(fā)則重新計時。 | 固定間隔執(zhí)行:無論事件觸發(fā)頻率如何,每隔固定時間必定執(zhí)行一次。 |
| 執(zhí)行時機 | 僅在最后一次觸發(fā)后的延遲時間結(jié)束后執(zhí)行。 | 在固定時間間隔內(nèi)至少執(zhí)行一次,可能多次觸發(fā)但只執(zhí)行一次。 |
| 適用場景 | 搜索框輸入、窗口調(diào)整結(jié)束、防重復(fù)提交等需要“等待穩(wěn)定”的場景。 | 滾動事件、鼠標(biāo)移動、動畫幀等需要“持續(xù)響應(yīng)”的場景。 |
| 延遲感 | 存在明顯延遲(用戶操作停止后等待執(zhí)行)。 | 響應(yīng)更及時(固定間隔內(nèi)至少執(zhí)行一次)。 |
二、實現(xiàn)原理對比
1. 函數(shù)防抖的實現(xiàn)邏輯
- 關(guān)鍵點:通過
setTimeout延遲執(zhí)行,并在每次觸發(fā)時清除之前的定時器。 - 示例代碼:
function debounce(func, delay) { let timer = null; return function() { clearTimeout(timer); timer = setTimeout(() => { func.apply(this, arguments); }, delay); }; } - 類比:
想象你正在等待電梯,如果有人按下按鈕后,電梯到達前又有人按了按鈕,電梯會取消之前的指令,重新開始倒計時。只有當(dāng)電梯等待時間結(jié)束后,才會真正運行。
2. 函數(shù)節(jié)流的實現(xiàn)邏輯
- 關(guān)鍵點:通過時間戳或標(biāo)志位記錄上次執(zhí)行時間,確保在固定間隔內(nèi)最多執(zhí)行一次。
- 示例代碼(時間戳版):
function throttle(func, interval) { let lastTime = 0; return function() { const now = Date.now(); if (now - lastTime >= interval) { func.apply(this, arguments); lastTime = now; } }; } - 類比:
想象你正在接水,水龍頭每秒只能放一次水。無論你多么頻繁地打開水龍頭,水只會以固定的時間間隔流出。
三、適用場景對比
1. 函數(shù)防抖的適用場景
- 搜索框輸入聯(lián)想:
用戶輸入時,等待用戶停止輸入后再發(fā)送請求(如等待 300ms 后搜索),避免每次輸入都觸發(fā)請求。 - 窗口調(diào)整結(jié)束:
監(jiān)聽resize事件時,等待用戶停止拖動窗口后再調(diào)整布局。 - 防重復(fù)提交:
防止用戶快速點擊按鈕多次提交表單。
2. 函數(shù)節(jié)流的適用場景
- 滾動事件處理:
監(jiān)聽scroll事件時,無論用戶滾動多快,每 200ms 最多執(zhí)行一次滾動邏輯(如懶加載、返回頂部按鈕顯示)。 - 鼠標(biāo)移動事件:
游戲開發(fā)中,限制鼠標(biāo)移動事件的觸發(fā)頻率,避免性能問題。 - 動畫幀控制:
通過requestAnimationFrame節(jié)流,確保動畫幀率穩(wěn)定。
四、實際案例對比
1. 搜索框輸入
- 防抖:
用戶輸入"hello"時,若每 100ms 輸入一個字母,防抖會等待 300ms 后才發(fā)送"hello"的請求。 - 節(jié)流:
用戶輸入"hello"時,若每 100ms 輸入一個字母,節(jié)流可能只發(fā)送"h"、"he"、"hel"等部分請求(取決于間隔設(shè)置),導(dǎo)致搜索結(jié)果不準(zhǔn)確。
2. 滾動加載
- 防抖:
用戶快速滾動頁面時,防抖會等待滾動停止后才加載數(shù)據(jù),導(dǎo)致用戶看到空白區(qū)域。 - 節(jié)流:
用戶快速滾動頁面時,節(jié)流會每隔固定時間加載一次數(shù)據(jù),確保頁面內(nèi)容持續(xù)更新。
五、優(yōu)缺點對比
| 技術(shù) | 優(yōu)點 | 缺點 |
|---|---|---|
| 防抖 | - 避免高頻執(zhí)行,減少資源消耗。 - 適用于需要“等待穩(wěn)定”的場景。 | - 存在延遲,用戶體驗可能不流暢(如搜索框輸入后需等待)。 |
| 節(jié)流 | - 確保固定間隔內(nèi)至少執(zhí)行一次,響應(yīng)更及時。 - 適用于需要“持續(xù)響應(yīng)”的場景。 | - 無法完全避免高頻執(zhí)行(如用戶滾動極快時仍可能多次觸發(fā))。 |
六、如何選擇?
- 需要“等待穩(wěn)定”的場景 → 防抖
- 用戶操作完成后才執(zhí)行(如搜索框輸入、窗口調(diào)整結(jié)束)。
- 需要“持續(xù)響應(yīng)”的場景 → 節(jié)流
- 用戶操作過程中需要持續(xù)反饋(如滾動加載、鼠標(biāo)移動)。
- 組合使用
- 某些場景可能需要同時使用防抖和節(jié)流(如既要在滾動停止后加載數(shù)據(jù),又要在滾動過程中限制頻率)。
七、代碼示例對比
1. 防抖示例:搜索框輸入
const searchInput = document.getElementById('search');
const debouncedSearch = debounce(() => {
console.log('執(zhí)行搜索:', searchInput.value);
}, 300);
searchInput.addEventListener('input', debouncedSearch);
2. 節(jié)流示例:滾動加載
window.addEventListener('scroll', throttle(() => {
console.log('檢查滾動位置,加載數(shù)據(jù)');
// 懶加載邏輯
}, 200));
總結(jié)
- 函數(shù)防抖:適合“等待用戶操作完成”的場景,通過延遲執(zhí)行減少不必要的計算。
- 函數(shù)節(jié)流:適合“需要持續(xù)響應(yīng)”的場景,通過固定間隔執(zhí)行確保流暢的用戶體驗。
根據(jù)實際需求選擇合適的技術(shù),可以顯著提升頁面性能和用戶體驗。
到此這篇關(guān)于JavaScript函數(shù)防抖的文章就介紹到這了,更多相關(guān)JS函數(shù)防抖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
根據(jù)身份證號自動輸出相關(guān)信息(籍貫,出身日期,性別)
為了減少客戶的在頁面的輸入,做了這個效果,他可以根據(jù)用戶輸入的身份證號輸出籍貫、出身日期、性別的相關(guān)信息,需要的朋友可以參考下2013-11-11
微信小程序中使用ECharts 異步加載數(shù)據(jù)的方法
這篇文章主要介紹了微信小程序中使用ECharts 異步加載數(shù)據(jù)的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-06-06
Bootstrap基本組件學(xué)習(xí)筆記之下拉菜單(7)
這篇文章主要為大家詳細介紹了Bootstrap基本組件學(xué)習(xí)筆記之下拉菜單,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12

