JavaScript防抖與節流全解析

文章目錄

    • 前言:為什么需要防抖和節流
    • 基本概念與區別
      • 防抖(Debounce)
      • 節流(Throttle)
      • 關鍵區別
    • 防抖(Debounce)詳解
      • 1. 基本防抖函數實現
      • 2. 防抖函數的使用
      • 3. 防抖函數的工作流程
      • 4. 防抖函數進階 - 立即執行選項
    • 節流(Throttle)詳解
      • 1. 基本節流函數實現
        • 時間戳法(第一次會立即執行)
        • 定時器法(第一次會延遲執行)
      • 2. 節流函數的使用
      • 3. 節流函數的工作流程
      • 4. 節流函數進階 - 首尾調用控制
    • 實際應用場景
      • 1. 搜索框輸入防抖
      • 2. 滾動加載節流
      • 3. 按鈕點擊防抖(防止重復提交)
      • 4. 窗口調整大小節流
    • 防抖與節流的進階實現
      • 1. 可取消的防抖函數
      • 2. 可取消的節流函數
      • 3. 帶返回值的防抖函數(使用Promise)
    • 常見問題與解決方案
      • 1. 防抖函數內無法訪問this和事件對象
      • 2. React組件中使用防抖/節流
      • 3. 函數依賴項變化時重置防抖/節流
    • 第三方庫的實現
      • 1. Lodash
      • 2. Underscore
      • 3. RxJS
    • 總結與最佳實踐
      • 1. 選擇合適的技術
      • 2. 性能考慮
      • 3. 最佳實踐
      • 4. 回顧關鍵概念
      • 2. 性能考慮
      • 3. 最佳實踐
      • 4. 回顧關鍵概念

前言:為什么需要防抖和節流

在前端開發中,我們經常會遇到一些高頻觸發的事件,例如:

  • 瀏覽器窗口調整大小(resize)
  • 頁面滾動(scroll)
  • 鼠標移動(mousemove)
  • 鍵盤輸入(keyup、keydown)
  • 頻繁點擊按鈕等

如果不加控制,這些事件處理函數可能會在短時間內被頻繁調用,導致以下問題:

  1. 性能問題:函數頻繁執行,特別是復雜計算或DOM操作,會導致頁面卡頓
  2. 資源浪費:例如輸入搜索時,頻繁發送不必要的API請求
  3. 不良用戶體驗:例如按鈕重復點擊導致的重復提交表單

看一個具體例子:

// 不做任何處理的搜索輸入框
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', function() {// 每次輸入都會執行,即使用戶正在快速輸入console.log('執行搜索:', this.value);fetchSearchResults(this.value); // 發送請求獲取搜索結果
});

在上面的例子中,當用戶快速輸入"JavaScript"這個詞時,可能會依次觸發以下請求:

  • 搜索"J"
  • 搜索"Ja"
  • 搜索"Jav"
  • 搜索"Java"
  • 搜索"JavaS"
  • 搜索"JavaScript"

顯然,除了最后一個請求,前面的所有請求都是不必要的,這不僅浪費了網絡資源,還可能導致服務器壓力過大。

這就是為什么我們需要防抖和節流技術:它們幫助我們控制函數的執行頻率,優化性能和用戶體驗。

基本概念與區別

防抖(Debounce)

概念:函數防抖是指在事件被觸發n秒后再執行回調,如果在這n秒內事件又被觸發,則重新計時。

形象比喻:電梯關門 - 當有人進入電梯后,電梯會等待一段時間再關門,如果在這段時間內又有人進入,電梯會重新計時等待,直到一段時間內沒有人進入才會關門。

典型場景

  • 搜索框輸入,等用戶輸入完畢后再發送請求
  • 窗口調整大小完成后執行重排重繪
  • 按鈕提交事件防止重復提交

節流(Throttle)

概念:函數節流是指規定一個單位時間,在這個單位時間內,只能有一次觸發事件的回調函數執行,如果在同一個單位時間內某事件被觸發多次,只有一次能生效。

形象比喻:水龍頭控制水流 - 無論你如何快速地多次擰開水龍頭,水流速度都不會超過水管的限制。

典型場景

  • 滾動事件處理
  • 射擊游戲中的武器發射頻率限制
  • 鼠標移動事件處理

關鍵區別

特性防抖(Debounce)節流(Throttle)
執行時機在一段時間內沒有再次觸發事件后執行在一段時間內只執行一次
適用場景需要等待操作完全結束后執行需要保持一定的執行頻率
執行頻率不穩定,取決于事件觸發頻率和間隔穩定,保證一定時間內執行一次
最后一次是否執行延遲執行,一定會執行可能不會執行最后一次(取決于實現)

下面通過可視化圖表來理解兩者的區別:

連續事件觸發:
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
│ │ │ │ │ │ │ │ │ │
0 1 2 3 4 5 6 7 8 9 (時間軸)防抖(延遲3秒):
─────────────────────→ (只在最后一次事件后等待3秒執行)↓9+3=12節流(間隔3秒):
↓       ↓       ↓     (每隔3秒執行一次)
│       │       │
0       3       6     (時間軸)

防抖(Debounce)詳解

1. 基本防抖函數實現

/*** 基礎版防抖函數* @param {Function} func - 需要防抖的函數* @param {number} wait - 等待時間,單位毫秒* @returns {Function} - 防抖處理后的函數*/
function debounce(func, wait) {let timeout;return function() {const context = this; // 保存this指向const args = arguments; // 保存傳入的參數// 清除之前的定時器clearTimeout(timeout);// 設置新的定時器timeout = setTimeout(function() {func.apply(context, args);}, wait);};
}

2. 防抖函數的使用

// 定義一個可能頻繁調用的函數
function handleSearch(searchTerm) {console.log('Searching for:', searchTerm);// 發送API請求等操作...
}// 獲取輸入框元素
const searchInput = document.getElementById('search-input');// 未使用防抖的版本 - 每次輸入都會執行
/*
searchInput.addEventListener('input', function() {handleSearch(this.value);
});
*/// 使用防抖后的版本 - 停止輸入300毫秒后才執行
const debouncedSearch = debounce(function() {handleSearch(this.value);
}, 300);searchInput.addEventListener('input', debouncedSearch);

3. 防抖函數的工作流程

以搜索框為例,當用戶連續輸入"hello"這個詞:

時間軸: 0ms     100ms    200ms    300ms    400ms    700ms
操作:    h        e        l        l        o       (停止輸入)
函數調用: 無       無       無       無       無        執行搜索"hello"

每次按鍵都會重置定時器,只有當用戶停止輸入300ms后,才會執行一次搜索。

4. 防抖函數進階 - 立即執行選項

在某些場景下,我們可能希望第一次觸發事件時立即執行函數,然后等待一段時間再允許執行下一次。例如點擊提交按鈕時,我們希望立即響應第一次點擊,然后暫時禁用后續點擊。

/*** 帶立即執行選項的防抖函數* @param {Function} func - 需要防抖的函數* @param {number} wait - 等待時間,單位毫秒* @param {boolean} immediate - 是否立即執行* @returns {Function} - 防抖處理后的函數*/
function debounce(func, wait, immediate) {let timeout;return function() {const context = this;const args = arguments;const later = function() {timeout = null;if (!immediate) func.apply(context, args);};const callNow = immediate && !timeout;clearTimeout(timeout);timeout = setTimeout(later, wait);if (callNow) func.apply(context, args);};
}// 使用立即執行的防抖 - 第一次點擊立即響應,后續點擊被防抖
const button = document.getElementById('submit-button');
const immediateDebounceClick = debounce(function() {console.log('Button clicked!');// 提交表單等操作...
}, 1000, true);button.addEventListener('click', immediateDebounceClick);

節流(Throttle)詳解

1. 基本節流函數實現

有兩種常見的方式實現節流函數:時間戳法和定時器法。

時間戳法(第一次會立即執行)
/*** 時間戳實現的節流函數* @param {Function} func - 需要節流的函數* @param {number} wait - 等待時間,單位毫秒* @returns {Function} - 節流處理后的函數*/
function throttle(func, wait) {let previous = 0; // 上一次執行的時間戳return function() {const now = Date.now(); // 當前時間戳const context = this;const args = arguments;// 如果當前時間與上一次執行時間差大于等待時間if (now - previous > wait) {func.apply(context, args);previous = now;}};
}
定時器法(第一次會延遲執行)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/83551.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/83551.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/83551.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JavaScript入門【3】面向對象

1.對象: 1.概述: 在js中除了5中基本類型之外,剩下得都是對象Object類型(引用類型),他們的頂級父類是Object;2.形式: 在js中,對象類型的格式為key-value形式,key表示屬性,value表示屬性的值3.創建對象的方式: 方式1:通過new關鍵字創建(不常用) let person new Object();// 添…

oracle主備切換參考

主備正常切換操作參考:RAC兩節點->單機 (rac和單機的操作區別:就是關閉其它節點,剩一個節點操作即可) 1.主庫準備 檢查狀態 SQL> select inst_id,database_role,OPEN_MODE from gv$database; INST_ID DATA…

端到端自動駕駛系統實戰指南:從Comma.ai架構到PyTorch部署

引言:端到端自動駕駛的技術革命 在自動駕駛技術演進歷程中,端到端(End-to-End)架構正引領新一輪技術革命。不同于傳統分模塊處理感知、規劃、控制的方案,端到端系統通過深度神經網絡直接建立傳感器原始數據到車輛控制…

使用 Kotlin 和 Jetpack Compose 開發 Wear OS 應用的完整指南

環境配置與項目搭建 1. Gradle 依賴配置 // build.gradle (Module) android {buildFeatures {compose true}composeOptions {kotlinCompilerExtensionVersion "1.5.3"} }dependencies {def wear_compose_version "1.2.0"implementation "androidx.…

應用層協議簡介:以 HTTP 和 MQTT 為例

文章目錄 應用層協議簡介:什么是應用層協議?為什么需要應用層協議?什么是應用層協議?為什么需要應用層協議? HTTP 協議詳解HTTP 協議特點HTTP 工作的基本原理HTTP 請求與響應示例為什么 Web 應用基于 HTTP 請求&#x…

Kafka快速安裝與使用

引言 這篇文章是一篇Ubuntu(Linux)環境下的Kafka安裝與使用教程,通過本文,你可以非常快速搭建一個kafka的小單元進行日常開發與調測。 安裝步驟 下載與解壓安裝 首先我們需要下載一下Kafka,這里筆者采用wget指令: wget https:…

PD 分離推理的加速大招,百度智能云網絡基礎設施和通信組件的優化實踐

為了適應 PD 分離式推理部署架構,百度智能云從物理網絡層面的「4us 端到端低時延」HPN 集群建設,到網絡流量層面的設備配置和管理,再到通信組件和算子層面的優化,顯著提升了上層推理服務的整體性能。 百度智能云在大規模 PD 分離…

flutter Stream 有哪兩種訂閱模式。

Flutter 中的 Stream 有兩種訂閱模式: ?單訂閱模式 (Single Subscription)?? 只能有一個訂閱者(listen 只能調用一次),后續調用會拋出異常。數據僅在訂閱后開始傳遞,適用于點對點通信場景(如文件讀取流…

Python爬蟲實戰:研究JavaScript 環境補全逆向解密

1. 引言 1.1 研究背景與意義 隨著互聯網的快速發展,大量有價值的數據被發布在各種網站上。然而,為了保護數據安全和商業利益,許多網站采用了 JavaScript 加密技術對敏感數據進行保護。這些加密技術使得傳統的爬蟲技術難以直接獲取和解析數據,給數據采集工作帶來了巨大挑戰…

[system-design] ByteByteGo_Note Summary

目錄 通信協議 REST API 與 GraphQL gRPC 如何工作? 什么是Webhook? 如何提高應用程序接口的性能? HTTP 1.0 -> HTTP 1.1 -> HTTP 2.0 -> HTTP 3.0 (QUIC) SOAP vs REST vs GraphQL vs RPC 代碼優先與應用程序接口優先 HTT…

Linux中的進程

進程控制 fork 函數 fork 函數從已存在的進程中創建新的進程,已存在進程為父進程,新創建進程為子進程 fork 的常規用法 一個父進程希望復制自己,使父子進程同時執行不同的代碼段。例如,父進程等待客戶端請求,生成子…

EDR與XDR如何選擇適合您的網絡安全解決方案

1. 什么是EDR? 端點檢測與響應(EDR) 專注于保護端點設備(如電腦、服務器、移動設備)。通過在端點安裝代理軟件,EDR實時監控設備活動,檢測威脅并快速響應。 EDR核心功能 實時監控:…

AGI大模型(21):混合檢索之混合搜索

為了執行混合搜索,我們結合了 BM25 和密集檢索的結果。每種方法的分數均經過標準化和加權以獲得最佳總體結果 1 代碼 先編寫 BM25搜索的代碼,再編寫密集檢索的代碼,最后進行混合。 from rank_bm25 import BM25Okapi from nltk.tokenize import word_tokenize import jieb…

2025最新的軟件測試面試大全(含答案+文檔)

一、軟件測試基礎面試題 1、闡述軟件生命周期都有哪些階段? 常見的軟件生命周期模型有哪些? 軟件生命周期是指一個計算機軟件從功能確定設計,到開發成功投入使用,并在使用中不斷地修改、增補和完善,直到停止該軟件的使用的全過程(從醞釀到…

C++.神經網絡與深度學習(二次修改)

神經網絡與深度學習 1. 神經網絡基礎1.1 神經元模型與激活函數1.2 神經網絡結構與前向傳播2.1 損失函數與優化算法均方誤差損失函數交叉熵損失函數梯度下降優化算法2.2 反向傳播與梯度計算神經元的反向傳播3.1 神經元類設計與實現神經元類代碼實現代碼思路3.2 神經網絡類構建神…

FPGA圖像處理(六)------ 圖像腐蝕and圖像膨脹

默認迭代次數為1,只進行一次腐蝕、膨脹 一、圖像腐蝕 1.相關定義 2.圖像腐蝕效果圖 3.fpga實現 彩色圖像灰度化,灰度圖像二值化,圖像緩存生成濾波模塊(3*3),圖像腐蝕算法 timescale 1ns / 1ps // // Des…

中國版Cursor:CodeBuddy騰訊云代碼助手使用體驗

我正在參加CodeBuddy「首席試玩官」內容創作大賽,本文所使用的 CodeBuddy 免費下載鏈接:騰訊云代碼助手 CodeBuddy - AI 時代的智能編程伙伴” 1.CodeBuddy簡介 騰訊云代碼助手CodeBuddy,這個是一款編程插件,我們可以在各個編程…

Go語言 GORM框架 使用指南

在 Go 語言社區中,數據庫交互一直是開發者們關注的重點領域,不同開發者基于自身的需求和偏好,形成了兩種主要的技術選型流派。一部分開發者鐘情于像sqlx這類簡潔的庫,盡管其功能并非一應俱全,但它賦予開發者對 SQL 語句…

從零開始學習three.js(18):一文詳解three.js中的著色器Shader

在WebGL和Three.js的3D圖形渲染中,著色器(Shader) 是實現復雜視覺效果的核心工具。通過編寫自定義的著色器代碼,開發者可以直接操作GPU,實現從基礎顏色渲染到動態光照、粒子效果等高級圖形技術。本文將深入解析Three.j…

Python函數庫調用實戰:以數據分析為例

一、引言 Python之所以在編程領域廣受歡迎,很大程度上得益于其豐富且強大的函數庫。這些函數庫涵蓋了從數據分析、科學計算到Web開發、機器學習等眾多領域,極大地提高了開發效率。本文將以數據分析為例,介紹如何調用Python的一些常用函數庫。…