防抖 Debouncing 深度解析一个定时器如何吞掉 20 次调用【免费下载链接】30-seconds-of-interviewsA curated collection of common interview questions to help you prepare for your next interview.项目地址: https://gitcode.com/gh_mirrors/30/30-seconds-of-interviews搜索框每按一个键就发一次请求、滚动监听每秒触发 20 多次重活还在傻跑——这是前端高频事件的常见事故现场。防抖Debouncing就是为此而生的事件不停代码不跑事件一停才执行一次。开源面试题库 30-seconds-of-interviews 用一份 Markdown 题目文件就把这套机制讲完了下面从事故现场到仓库管线完整走一遍。先花 30 秒拿住核心防抖的本质把时间窗口内的多次连续调用合并成窗口结束后的一次执行裸 DOM 事件监听器每秒可以轻松触发 20 次防抖版只在延迟期满后调用一次全部实现就两个 APIclearTimeoutsetTimeout外加一个用闭包Closure保存的定时器句柄判断标准事件还在密集触发定时器永远到不了期事件停了最后一个定时器走完目标函数执行恰好一次经典落点搜索输入停键后才发 API 请求、scroll/resize处理降频。机制对读定时器被反复清零的游戏想象一个带自动闭门器的门。你每推它一次闭门器就重新归位、重新计时只有当你有一段时间不推门它才唰地关上。防抖就是给函数装了这么个闭门器第 1 次调用启动一个delay毫秒的定时器delay内又来第 2 次调用先clearTimeout掐掉上一个再重新计时事件持续到来定时器被反复清零目标函数一次都没跑事件停止最后一个定时器独自走完——函数执行恰好一次且拿到的是最后一次调用的参数。关键在于定时器句柄存在哪它必须在返回函数的外层作用域里闭包下一次调用才拿得到上一次的句柄去清除。句柄若声明在内层每次调用都是一个新值clearTimeout永远清不到东西合并能力直接失效。动手实现12 行可跑的防抖下面是仓库题目给出的标准实现原样引用注意原文addEventListere为拼写错误应为addEventListenerconst debounce (func, delay) { let debounceTimer; // 闭包保存定时器句柄 return function() { const context this; // 捕获调用时的 this const args arguments; // 捕获全部实参 clearTimeout(debounceTimer); // 掐掉上一次未到的定时器 debounceTimer setTimeout(() func.apply(context, args), delay); } } window.addEventListener(scroll, debounce(function() { // Do stuff, this function will be called after a delay of 1 second }, 1000));逐行说人话let debounceTimer声明在返回函数之外靠闭包跨调用存活是重置能力的前提clearTimeout必须在setTimeout之前执行顺序反了就白搭context/args加上func.apply包装层原样透传调用现场不改写目标函数的语义用法上debounce(fn, 1000)返回的是新的包装函数挂到scroll上的是它1 秒后用户停止滚动真实回调才执行一次。工程账本优化前 vs 优化后以输入 react 这 5 个字符每键发一次搜索请求为例维度不加防抖300ms 防抖网络请求次数5 次1 次用户体感连续刷新结果旧响应可能覆盖新结果停顿后出一次结果稳定主线程负担每次按键都渲染仅末态渲染一次再对照滚动场景题目里明确裸监听器每秒可触发 20 次防抖后一段连续滚动只结算一次。两个场景共同指向同一条原则——以末态为准的事末次搜索词、末次视口尺寸交给防抖最划算。追问时间面试官真正想听的部分追问 1防抖 vs 节流边界在哪对比项防抖debounce节流throttle执行时机调用停止后延迟执行一次固定间隔内至多一次控制对象窗口内的调用次数执行的频率上限典型场景搜索、resize 后重排拖拽、滚动进度、游戏循环末态保证保证用最后一次参数不保证可能丢末态记忆锚点要末态选防抖要保底频率选节流。追问 2this和参数为什么单独接住外层return function()必须是普通函数而非箭头函数——事件监听器里this是动态的窗口或绑定元素箭头函数会把它锁死成定义时的作用域arguments则原样接住所有实参最后经func.apply一次性透传。追问 3首次调用能立即执行吗能这就是 leading edge 模式首次调用直接执行之后进入冷却期忽略后续调用delay结束才解锁。但仓库给出的标准实现是 trailing末次执行面试先答这个再主动补一句需要首触立即执行时可用 leading 版层次就出来了。项目视角这道题在仓库里走了哪条链路questions/debouncing.md——内容源。含#### Answer、#### Good to hear等固定小节格式约定见 question-template.md另有!-- tags: --、!-- expertise: --隐藏注释承载标签与难度scripts/util.js——解析工具层。readQuestions()按字母序读取整个questions/目录getSection()按标题切块getCodeBlocks()抽取代码块scripts/extract.js——管线核心。把每题的 question / answer / goodToHear / 难度 / 代码块组装成对象写入data/questions.json对应package.json里的extractor: node ./scripts/extract.jsdata/questions.json——数据文件前端唯一数据源由 website/js/state.js 直接 import 进 Hyperapp 状态website/js/components/——展示层Filter.js管标签过滤Questions.js负责按难度排序渲染列表Question.js展开单题Markdown.js用 marked 渲染答案、Prism 高亮代码。一条冷知识可以加分当前提交的data/questions.json只有 103 道题而questions/目录已有 109 个 md 文件debouncing.md还没进数据——这道题是在数据快照之后加入的重跑一次extractor脚本它就会出现在网站上。自测卡片防抖一次触发里clearTimeout和setTimeout各执行几次持续滚动 3 秒后停止delay1000ms回调执行几次外层返回箭头函数会丢掉什么需要保证每 100ms 至少执行一次的场景该选防抖还是节流关键词收束防抖Debouncing、clearTimeoutsetTimeout、闭包状态、末态合并、防抖和节流的区别debounce vs throttle。【免费下载链接】30-seconds-of-interviewsA curated collection of common interview questions to help you prepare for your next interview.项目地址: https://gitcode.com/gh_mirrors/30/30-seconds-of-interviews创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考