面試復盤:節流中第二次觸發的事件?答錯補課
背景描述
今天面試時被問到一個看似基礎但暗藏玄機的問題:“節流(Throttle)函數中,第二次觸發的那一幀事件是否會被丟掉?” 我基于對經典節流實現的理解,自信地回答:“會被丟掉”。但面試官卻用滾動條進行追問,應該是在暗示我的回答不全面(我確實沒有get到,還很疑惑,難道答錯了?)。這場交鋒讓我意識到自己對節流的理解還很表面,下面復盤核心知識點。
一、問題本質:面試官在考察什么?
面試官并非質疑“節流會限制執行頻率”這一基礎概念,而是考察了兩個關鍵點:
- 是否理解節流的多種實現策略(時間戳、定時器、組合模式),而非死記“固定間隔執行一次”(我確實只記得這個);
- 能否根據場景選擇策略,尤其是滾動這類需要兼顧首尾操作連續性的場景。
當他說“滾動條似乎覺得不對”時,其實在提示:滾動場景常用組合版節流(首尾執行),此時最后一次觸發會被保留。
二、為什么我的回答“會被丟掉”不嚴謹?
我的回答在部分節流場景中成立,但忽略了關鍵差異:
節流實現策略 | 第二次觸發是否丟棄 | 原理 | 適用場景 |
---|---|---|---|
時間戳版 | ? 丟棄 | 基于時間差判斷:若距離上次執行未達間隔,直接丟棄所有中間觸發 | 按鈕點擊、即時反饋 |
定時器版 | ? 丟棄 | 通過setTimeout 鎖住執行狀態:間隔內新觸發無法覆蓋已有定時器 | 延遲響應(如動畫結束) |
組合版 | ?? 可能保留 | 若第二次觸發發生在間隔末尾且是最后一次操作,會新建定時器延遲執行 | 滾動加載、窗口resize |
滾動條場景的特殊性:
用戶滾動時既需要即時反饋(如滾動條位置更新),又需要確保滾動結束狀態被捕獲(如懶加載圖片)。組合版通過“首次立即執行 + 末次延遲執行”滿足這個場景的需求。
三、組合版節流如何保留第二次觸發?(核心原理)
面試官提到的滾動條場景,正是組合版節流的典型應用。其關鍵邏輯在于:
- 首次觸發立即執行:快速響應用戶操作;
- 間隔內的末次觸發延遲執行:通過計算剩余時間(
remaining
),為最后一次操作創建定時器:
function throttle(fn, interval) {let timer = null;let lastTime = 0;return function(...args) {const now = Date.now();const remaining = interval - (now - lastTime); // 計算剩余時間if (remaining <= 0) { // 超過間隔:立即執行并清除舊定時器if (timer) clearTimeout(timer);fn.apply(this, args);lastTime = now;} else if (!timer) { // 間隔內且無定時器:為最后一次觸發設置新定時器timer = setTimeout(() => {fn.apply(this, args);lastTime = Date.now();timer = null;}, remaining);}};
}
當用戶快速滾動時:
- 首次滾動觸發立即執行;
- 后續滾動若在間隔結束前再次觸發(如300ms內),會清除舊定時器,為最后一次觸發設置新定時器;
- 若該次觸發是最后一次操作,則間隔結束后仍會執行。
四、正確回答思路(思路模板)
下次遇到這個問題,要分層回答:
“節流對第二次觸發的處理取決于具體實現策略:
- 時間戳/基礎定時器版:間隔內第二次觸發會被丟棄;
- 組合版(推薦):若第二次觸發發生在間隔末尾且是最后一次操作,會通過新定時器延遲執行(例如滾動條在滾動結束時需捕獲位置)。
面試官暗示提到滾動條,是因為這類場景中常用的組合模式,這種情況,第二次觸發是可能被保留的——這是為保障操作完整性的特殊設計。”
延伸補充:
- 性能和完整性處理:丟棄中間觸發是為節省計算資源(如避免高頻DOM操作),但滾動等連續操作需優先保障終止狀態捕獲;
- “幀”概念的澄清:瀏覽器渲染幀(16.6ms)≠ 節流間隔,后者是人為設定的時間閾值(如200ms)(聽到幀的時候我都懵了,根本沒想起來滾動條的定時器設置)。
五、總結:考察點
- 場景決定技術選型:滾動、拖拽等連續操作需用組合版節流,確保首尾響應;表單提交/按鈕防抖則適用基礎版;
- 深入理解開源庫:Lodash的
_.throttle
默認采用組合模式,其trailing: true
選項即控制是否執行末次觸發; - 溝通技巧:若不確定場景,可反問:“您提到的場景是否需要兼顧最后一次操作?我們可能需用組合版節流” —— 主動思考比標準答案更重要。
關鍵教訓:前端API的實現常因場景而異。死記“節流就是間隔執行一次”易踩坑。
參考資料:
- 節流三種模式對比: 防抖 & 節流原理
- 深入理解JavaScript中的節流與防抖:從原理到實踐
- 滾動時對象頻繁重載?解決方法大揭秘!