最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript如何利用防抖與節(jié)流優(yōu)化網(wǎng)頁性能

 更新時間:2025年08月17日 09:04:07   作者:盛夏綻放  
這篇文章主要為大家詳細介紹了JavaScript中防抖與節(jié)流的相關(guān)知識,并利用它們進行網(wǎng)頁性能優(yōu)化,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

引言:當(dāng)"狂點族"遇上網(wǎng)頁性能

想象一下這個場景:小美正在雙十一搶購,瘋狂點擊"立即購買"按鈕;老王在調(diào)整瀏覽器窗口大小時,頁面元素不斷重新計算;小李在搜索框邊輸入邊觸發(fā)搜索…如果沒有防抖和節(jié)流,這些操作會讓網(wǎng)頁像背著10斤重的書包跑步一樣喘不過氣來!

電商網(wǎng)站搜索框場景

用戶輸入"最新智能手機"時:

  • 無優(yōu)化:觸發(fā)6次搜索請求(每個字符一次)
  • 防抖:只在停止輸入300ms后觸發(fā)1次
  • 節(jié)流:每200ms最多觸發(fā)1次(可能觸發(fā)3-4次)

沒有它們會怎樣?

場景問題后果
連續(xù)點擊提交按鈕多次提交表單重復(fù)訂單、服務(wù)器壓力大
窗口頻繁調(diào)整大小持續(xù)觸發(fā)resize事件頁面卡頓、CPU占用高
輸入框?qū)崟r搜索每次輸入都請求API請求風(fēng)暴、性能浪費

一、防抖(debounce):給"多動癥"事件設(shè)置冷靜期

1.1 什么是防抖

“等你說完我再行動” - 就像電梯關(guān)門按鈕,無論按多少次,只會在最后一次操作后等待一段時間才執(zhí)行。

1.2 實現(xiàn)代碼(帶詳細注釋)

模式一:延遲執(zhí)行(經(jīng)典防抖)

/**
 * 經(jīng)典防抖:最后一次觸發(fā)后等待delay毫秒執(zhí)行
 * @param {Function} fn - 目標(biāo)函數(shù)
 * @param {number} delay - 延遲時間(ms)
 * @returns {Function} - 防抖處理后的函數(shù)
*/
function debounce(fn, delay) {
  // 用于保存定時器ID的閉包變量
  let timer;

  // 返回一個包裝后的新函數(shù)
  return function(...args) {
    // 如果已存在定時器,先清除之前的(避免多次觸發(fā))
    if (timer) clearTimeout(timer);

    // 設(shè)置新的定時器,在延遲時間后執(zhí)行原函數(shù)
    timer = setTimeout(() => {
      // 使用apply保持原函數(shù)的this指向和參數(shù)
      fn.apply(this, args);
      // 執(zhí)行后重置定時器變量(非必須,但有助于垃圾回收)
      timer = null;
    }, delay);
  };
}

模式二:立即執(zhí)行+冷卻

/**
 * 立即執(zhí)行版防抖:首次觸發(fā)立即執(zhí)行,之后進入冷卻期
 * @param {Function} fn    - 需要防抖的原始函數(shù)
 * @param {number}  wait   - 冷卻時間(毫秒)
 * @returns {Function}     - 經(jīng)過防抖處理的新函數(shù)
 */
function debounceImmediate(fn, wait) {
  // 用于保存定時器 ID 的閉包變量
  let timer;

  // 返回一個包裝后的新函數(shù)
  return function (...args) {
    // 如果已經(jīng)有定時器,先清除(重置冷卻期)
    if (timer) clearTimeout(timer);

    // 判斷是否應(yīng)該立即執(zhí)行
    // 當(dāng) timer 為 null/undefined 時(即首次觸發(fā)或已冷卻完畢),shouldCallNow 為 true
    const shouldCallNow = !timer;

    // 設(shè)置新的定時器
    // 定時器到期后把 timer 置空,表示冷卻期結(jié)束
    timer = setTimeout(() => {
      timer = null;
    }, wait);

    // 如果需要立即執(zhí)行,則立即調(diào)用原函數(shù)
    if (shouldCallNow) {
      fn.apply(this, args);
    }
  };
}

兩種模式對比表

特性延遲執(zhí)行模式立即執(zhí)行模式
首次觸發(fā)不執(zhí)行立即執(zhí)行
后續(xù)觸發(fā)重置計時,最后一次執(zhí)行冷卻期內(nèi)不執(zhí)行
執(zhí)行時機停止觸發(fā)后delay毫秒首次觸發(fā)立即執(zhí)行
適用場景搜索建議、窗口resize按鈕防重復(fù)點擊、表單提交

1.3 適用場景(表格對比)

場景不使用防抖使用防抖后
搜索框輸入輸入每個字符都觸發(fā)搜索停止輸入500ms后才搜索
窗口resize每次像素變化都計算布局調(diào)整結(jié)束300ms后計算
按鈕提交快速點擊導(dǎo)致多次提交只認最后一次點擊

二、節(jié)流(throttle):給事件加上"技能冷卻時間"

2.1 什么是節(jié)流

“再著急也得按節(jié)奏來” - 就像游戲中的技能CD,無論你按多快,技能都會按照固定頻率釋放。

2.2 實現(xiàn)代碼

方式1:定時器版(尾部執(zhí)行)

/**
 * 定時器版節(jié)流(保證周期末尾執(zhí)行)
 * @param {Function} fn - 需要節(jié)流的函數(shù)
 * @param {number} wait - 執(zhí)行間隔(ms)
 * @returns {Function} - 節(jié)流處理后的函數(shù)
 */
function throttleByTimer(fn, wait) {
    let timer = null;
    
    return function(...args) {
        const context = this;
        
        if (!timer) {
            timer = setTimeout(() => {
                fn.apply(context, args);
                timer = null;
            }, wait);
        }
    };
}

特點

  • 第一次觸發(fā)后會等待wait毫秒才執(zhí)行
  • 保證每個周期末尾會執(zhí)行一次
  • 停止觸發(fā)后可能還會執(zhí)行最后一次

執(zhí)行流程

事件觸發(fā): |--x--x---x----x------x---|
執(zhí)行時機: |----x----x----x----x-----|
           (固定間隔末尾執(zhí)行)

方式2:時間戳版(頭部執(zhí)行)

/**
 * 時間戳版節(jié)流(保證周期開始執(zhí)行)
 * @param {Function} fn - 需要節(jié)流的函數(shù)
 * @param {number} wait - 執(zhí)行間隔(ms)
 * @returns {Function} - 節(jié)流處理后的函數(shù)
 */
function throttleByTimestamp(fn, wait) {
    let prev = 0; // 上次執(zhí)行時間戳
    
    return function(...args) {
        const now = Date.now();
        
        if (now - prev >= wait) {
            fn.apply(this, args);
            prev = now;
        }
    };
}

特點

  • 第一次觸發(fā)立即執(zhí)行
  • 保證每個周期開始時執(zhí)行
  • 停止觸發(fā)后不會再有額外執(zhí)行

執(zhí)行流程

事件觸發(fā): |--x--x---x----x------x---|
執(zhí)行時機: |x----x----x----x---------|
           (固定間隔開始執(zhí)行)

兩種方式對比表格

特性定時器版時間戳版
首次觸發(fā)延遲執(zhí)行立即執(zhí)行
執(zhí)行時機周期末尾周期開始
停止觸發(fā)可能執(zhí)行最后一次不會執(zhí)行最后一次
實現(xiàn)方式使用setTimeout使用Date.now()
內(nèi)存占用需要維護timer變量只需維護prev時間戳
適用場景需要平滑結(jié)束的操作需要快速響應(yīng)的操作

2.3 防抖與節(jié)流對比(箭頭圖示)

高頻事件觸發(fā)場景:

      快速連續(xù)觸發(fā)事件
          ↓
防抖:└──────等待期──────┤執(zhí)行最后一次
          ↑ 期間觸發(fā)會重置等待期
          
節(jié)流:├─執(zhí)行─┼──間隔──┼─執(zhí)行─┤
         固定時間間隔必執(zhí)行

2.4 適用場景(表格對比)

場景推薦技術(shù)原因
搜索建議防抖用戶輸入完畢才響應(yīng)
無限滾動節(jié)流定期檢查滾動位置
拖拽元素節(jié)流保持流暢的UI更新
窗口resize防抖/節(jié)流防抖(最終布局)/節(jié)流(流暢調(diào)整)

三、防抖與節(jié)流的全方位對比

3.1 相同之處

共同點說明
控制執(zhí)行頻率兩者都能減少高頻事件的觸發(fā)次數(shù)
提升性能有效降低CPU使用率、減少不必要的函數(shù)調(diào)用
閉包應(yīng)用都利用閉包保存狀態(tài)(timer/lastTime)
返回新函數(shù)都是高階函數(shù),返回包裝后的函數(shù)

3.2 核心區(qū)別

特性防抖(debounce)節(jié)流(throttle)
執(zhí)行時機最后一次觸發(fā)后延遲執(zhí)行固定間隔執(zhí)行
重置機制新觸發(fā)會重置計時新觸發(fā)不影響既定節(jié)奏
保證執(zhí)行快速連續(xù)觸發(fā)時可能永不執(zhí)行必定會按節(jié)奏執(zhí)行
內(nèi)存占用需要維護單個timer需要維護timer+lastTime
適用場景關(guān)注最終狀態(tài)(如搜索)關(guān)注過程狀態(tài)(如滾動)

四、性能優(yōu)化數(shù)據(jù)對比

通過Chrome DevTools測試相同場景:

操作原生事件防抖處理節(jié)流處理
輸入100個字符100次調(diào)用1次調(diào)用20次調(diào)用(每5字符)
持續(xù)滾動10秒500+次調(diào)用1次調(diào)用10次調(diào)用(每秒1次)
CPU占用峰值85%15%30%

結(jié)語:成為性能優(yōu)化大師

防抖和節(jié)流就像前端開發(fā)中的"呼吸法":

  • 防抖是深呼氣后的暫停(等待穩(wěn)定)
  • 節(jié)流是均勻的腹式呼吸(保持節(jié)奏)

記住這個開發(fā)者口訣:

“高頻事件要優(yōu)化,防抖節(jié)流來幫忙;
輸入搜索用防抖,滾動動畫節(jié)流上;
參數(shù)調(diào)優(yōu)看場景,組合使用更健康!”

現(xiàn)在,打開你的開發(fā)者工具,找到那些"氣喘吁吁"的事件處理器,用合適的策略給它們裝上"呼吸調(diào)節(jié)器"吧! 

到此這篇關(guān)于JavaScript如何利用防抖與節(jié)流優(yōu)化網(wǎng)頁性能的文章就介紹到這了,更多相關(guān)JavaScript防抖與節(jié)流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

清新县| 通辽市| 曲水县| 阜平县| 二连浩特市| 桂平市| 汶上县| 上栗县| 高阳县| 盐山县| 峨眉山市| 安康市| 德格县| 汶上县| 肇东市| 合作市| 思茅市| 宣城市| 荆门市| 临城县| 柳州市| 伊金霍洛旗| 锦州市| 达拉特旗| 龙江县| 临西县| 错那县| 潼南县| 辽源市| 中方县| 和田市| 凤山市| 田林县| 阜新| 建德市| 克拉玛依市| 河北区| 高碑店市| 新邵县| 夏河县| 汤阴县|