中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

【每日一面(mian)】手寫(xie)防抖函數

基礎問答

問:手寫一個防抖函數
答:

/**
 * 基礎版防抖函數(非立即執行)
 * @param {Function} func - 需要防抖的目標函數
 * @param {number} delay - 等待時間(毫秒)
 * @returns {Function} - 防抖后的函數
 */
function debounce(func, delay) {
  let timer = null; // 用閉包存儲定時器ID,確保多次調用共享同一個定時器

  // 返回防抖后的函數,接收目標函數的參數(...args)
  return function (...args) {
    // 1. 若已有定時器,先清除(重復觸發時重新計時)
    if (timer) clearTimeout(timer);

    // 2. 重新設置定時器,等待delay后執行目標函數
    timer = setTimeout(() => {
      func.apply(this, args); // 用apply綁定this(確保目標函數this指向正確)
      timer = null; // 執行后清空定時器,避免內存泄漏
    }, delay);
  };
}

擴展延伸

防抖(Debounce)

  • 核心邏輯:當一個事件會被頻繁的觸發時,防抖函數不會頻繁的執行,而是等待事件停止觸發一段時間后才執行;如果在等待執行的過程中,事件再次被觸發,則我們需要重新計算需要等待的時間。
  • 典型使用場景:搜索框輸入聯想(每次按鍵都會觸發輸入對應 Input 的事件,我們認為用戶結束輸入后,我們再進行聯想,這個結束輸入的判定規則就是,自上一次Input事件觸發后的一段時間內,用戶沒有再觸發Input事件,可視為結束輸入,需要開始聯想),實時輸入校驗等。

和(he)防抖并列(lie)提及(ji)的是節流(liu)。

節流(Throttle)

  • 核心邏輯:當事件會被頻繁觸發的時候,節流函數只會按照固定的時間間隔執行,無論期間事件被處罰多少次,都只在每個時間的開頭(或結束)執行一次。
  • 典型使用場景:滾動監聽(一般用于加載數據判斷,每隔一段時間判斷一次當前位置,來判斷需要加載的數據量),窗口resize事件(用于重新計算布局)

這里簡單(dan)對比一下(xia)防(fang)抖和節流:

防抖 節流
執行時機 事件停止觸發后,等待一段指定的時間 固定時間間隔執行,每個時間段內僅執行一次
重復觸發的問題 重新計算等待的時間,執行會延遲 不影響,固定時間間隔執行
目標 解決冗余的執行 解決過度的執行
使用場景 搜索、校驗 滾動加載

搜索輸入的過程中,每次鍵入字符觸發搜索,在沒有防抖的情況下,僅僅只有最后一次的搜索(即用戶輸入完成)才是有效的,之前的這些,全部都是沒有意義的,只會加重服務負擔,即為 “冗余”

頁面滾動過程中,滾動是持續觸發的,在沒有節流的情況下,每一次滾動都會有大量的計算過程(假設你的滾動事件是有計算操作的),計算阻塞主線程,會導致頁面卡頓,無法正常滾動,即為 “過度” ,如果使(shi)用防(fang)抖(dou),滾動(dong)事件(jian)的持續觸(chu)發,會導致計算一直無法開始(shi),俗稱“不(bu)跟手(shou)”。

面試追問

  1. setTimeout 的延時并不準,有沒有辦法實現一個更精確的時間檢測?
    有,使用時間戳 + requestFrameAnimation 實現。

  2. 頁面滾動加載數據一般用什么?搜索框輸入觸發聯想詞,又用什么?
    滾動加載一般用節流,防抖需要等用戶停止滾動才加載,可能會等很久,節流則是一到底部就加載,可以保證加載的及時性。
    搜索聯(lian)想(xiang)一般用(yong)防(fang)抖,因(yin)為用(yong)戶的(de)輸(shu)入(ru)過程(cheng)會頻繁觸(chu)發聯(lian)想(xiang),但(dan)是(shi)只有(you)用(yong)戶停(ting)止輸(shu)入(ru)時,觸(chu)發的(de)聯(lian)想(xiang)才是(shi)用(yong)戶想(xiang)要的(de)、有(you)效(xiao)的(de)。

  3. 我看你在防抖函數中,用了 apply 這是為啥?為啥不可以直接用 func ?
    主要是(shi)(shi) this 指針的(de)(de)指向(xiang)問題(ti),防抖函(han)數返回的(de)(de)是(shi)(shi)一(yi)個新的(de)(de)函(han)數,假設現在設置的(de)(de)是(shi)(shi) input.oninput = debounceSearch,這(zhe)個 debounceSearch 中如果有 this,那么預期(qi)是(shi)(shi)要指向(xiang) input 標簽,但(dan)是(shi)(shi)我們(men)直接調用 func 的(de)(de)話,this 會指向(xiang) window 或 undefined,和預期(qi)不一(yi)致。

  4. 防抖函數中,如果目標函數有返回值,我們可以拿到嗎?
    不行(xing)(xing)(xing),即(ji)使返回(hui)目標函數結(jie)果也(ye)不行(xing)(xing)(xing),因為他(ta)在(zai) setTimeout 里面執行(xing)(xing)(xing)的(de),無法返回(hui)對應的(de)執行(xing)(xing)(xing)結(jie)果。

  5. 但是我就需要這個返回結果,有沒有辦法?
    有,兩(liang)種辦法,一是將(jiang) setTimout 用(yong)(yong) Promise 封裝起來,setTimeout 的(de)回調(diao)執行(xing)時,resolve 這個(ge)(ge) Promise 就可以了,這樣(yang)防抖函數就變成(cheng)了一個(ge)(ge)異步的(de)api,二是使用(yong)(yong)回調(diao)參數,在目標函數執行(xing)后,調(diao)用(yong)(yong)這個(ge)(ge)回調(diao)就可以了。

  6. 有沒有遇到過防抖函數導致內存泄漏的情況?
    沒有,但(dan)是防抖函數有內存泄漏的(de)可能性,本質(zhi)上是閉包寫法產生的(de),編寫代碼的(de)時候注(zhu)意閉包的(de)處理就可以了。

posted @ 2025-10-27 10:52  Achieve前端實驗室  閱讀(364)  評論(0)    收藏  舉報