防抖 Debouncing 完整指南从一次真实卡顿到手写实现【免费下载链接】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在 30-seconds-of-interviews 这份前端面试题库里“What is debouncing?”是 JavaScript 方向出场率最高的一道题。本文不打算先背定义而是从一个大家都踩过的现场开始一个每敲一个键就发一次请求的筛选框。从一次卡顿说起高频事件为什么打满主线程这节回答一个问题为什么朴素的事件监听器会把页面拖得这么卡想象一个商品列表的关键词筛选框input事件一触发就fetch解析响应再重新渲染列表。用户敲 react 五个字符就发了 5 个请求、重排了 5 次列表而用户真正在意的只有最后一次。scroll这类高频事件更夸张——仓库题目里给了个数字裸的 DOM 事件监听器每秒能轻松触发 20 次事件。如果在scroll监听里直接做布局计算、写存储回调本身就会一直占着主线程浏览器来不及完成一帧绘制用户看到的就是肉眼可见的卡顿。所以问题不在逻辑写错了而在逻辑跑得太多。那防抖函数凭什么让同样的逻辑只跑一次用电梯关门逻辑理解防抖原理这节回答怎么把“执行太多次”变成“只执行一次”想想电梯门快关门时只要有人再按开门键门就重新拉开、再次延迟关门直到没人再按门才真正合上。防抖借的就是这套“安静下来才动作”的思路——每来一次触发就重置定时器只有当触发停歇、连续 delay 毫秒都没有新的到来定时器才终于走完目标函数被执行一次。说白了防抖就是给函数按下“稍等”键触发来得越密执行就被推得越靠后最终整串高频触发只留下一次调用。仓库题目给出的标准实现只有十几行重点不是照抄而是搞清下面几个机制各自负责什么。手写防抖实现只讲透三个关键机制这节直接给一份可运行的完整实现然后只聚焦支撑它的三个机制不做逐行罗列。function debounce(fn, wait) { let timer null; return function (...args) { const ctx this; clearTimeout(timer); timer setTimeout(() fn.apply(ctx, args), wait); }; }机制一闭包保存“定时器句柄”。timer声明在返回函数之外活在debounce自己的作用域里。每次调用返回的函数时都能读到上一次留下的timer并把它改掉——这是“能重置”的前提。没有闭包每次调用都会拿到一个全新的timer变量上一句定时器就永远取消不了了。机制二clearTimeout 永远先跑。每次触发都先清掉上一个没到期的定时器再重新挂一个新的。只要事件还在高频到来定时器就永远在到期前被掐掉fn一次也不会执行直到事件停歇最后一次挂上的定时器顺利走完fn才执行一次。先清后挂这个顺序就是防抖的全部核心。机制三this 与参数透传。返回的函数刻意用普通函数而不是箭头函数为了捕获调用那一刻的this比如监听器里绑定的 DOM 元素再把实参存进args最后fn.apply(ctx, args)把原来的调用现场完整还原。少了这一步被包装的函数会悄悄丢掉上下文和参数。 注意这里的“内外有别”外层用普通函数捕获动态的this内层setTimeout的回调反而用箭头函数让ctx和args稳定地待在闭包里。两层搞混调用语义就变了。防抖实战给自动保存加上 800ms 缓冲这节用一个真实业务场景说明防抖到底省掉了什么。表单页的“草稿自动保存”很典型用户停止输入后把最新内容提交到服务端一次就够了。const editor document.querySelector(#draft); const saveDraft debounce(() { fetch(/api/draft, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ content: editor.value }), }); }, 800); editor.addEventListener(input, saveDraft);不加防抖时用户连敲 50 个字就冲出去 50 个 POST服务端收到一堆中间状态绝大多数没有意义加上 800ms 缓冲后通常只有 1 个请求落地而且就是最终状态。省下的不只是带宽更重要的是消除了“旧响应覆盖新结果”的竞态主线程也不会被反复的序列化和发送占满。scroll和resize同理想等窗口停止缩放后再重排一次布局把监听器包一层debounce就行。防抖和节流的区别一张表 三个高频追问快答这节回答面试官最爱连问的两个问题防抖和节流差在哪你会不会扩展它对比项防抖debounce节流throttle何时执行事件停歇、安静窗口过后执行一次固定间隔内最多执行一次首次触发默认不执行trailing可以立即执行一次leading窗口内执行次数无论触发多少次只留一次按保底频率持续执行适合场景输入搜索、resize 重排、自动保存滚动加载、拖拽、进度上报一句话记忆把“一段事件”压缩成一次给“执行频率”装上限三个高频追问快速过一遍leading 与 trailing 模式要哪个默认实现是 trailing——安静之后才执行。如果想要“第一次点击立即响应随后连点全部忽略”按钮防连点、轮播只上报首帧点击加一个immediate选项即可function debounce(fn, wait, immediate false) { let timer null; const run function (...args) { const callNow immediate timer null; clearTimeout(timer); timer setTimeout(() { timer null; if (!immediate) fn.apply(this, args); }, wait); if (callNow) fn.apply(this, args); }; run.cancel () { clearTimeout(timer); timer null; }; return run; }immediate true时“定时器是否存在”充当冷却期标记首次调用立即执行timer存活期间后续触发一律丢弃延迟结束后timer归位才允许下一次立即执行。cancel 取消机制别忘了清理⚠️ 这里有个坑防抖函数最好暴露一个cancel。组件卸载时挂起的定时器还在一旦触发就会操作已经不存在的 DOM。一行clearTimeout就能让它安静离场上面这段代码已经顺手带上了。this 与参数透传的坑为什么不能整体换成箭头函数外层必须用普通函数捕获动态的this内层setTimeout回调用箭头函数是为了把ctx、args钉在闭包里。顺序颠倒上下文就丢了。防抖自检三问你能现场手写吗这节不给你背清单而是把要点变成三个问题——能当场答全这道题就算过关了。自检问题应该能答出为什么页面会卡事件以 20 次/秒的密度派发回调执行太多次占满主线程防抖的灵魂是哪两行clearTimeout先清旧定时器setTimeout再挂新的只有最后一个能到期ctx/args是干什么的透传原函数的this与实参保证包装后调用语义不变顺带一提这道题在仓库里的链路是这样的题目正文存放在 questions/debouncing.md由 scripts/extract.js 拆出 Answer、Good to hear 等章节写入 data/questions.json 后交给网站前端渲染成可检索的题库。换到任何一端看答案的骨架都不变事件安静下来才执行一次。【免费下载链接】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),仅供参考
企业数字化 ERP 产品动态
相关推荐
Jasna 视频修复 GUI 完全指南:如何搞定系统检查、批量处理与激活排错的 5 个高频问题 Jasna 视频修复 GUI 完全指南:如何搞定系统检查、批量处理与激活排错的 5 个高频问题 【免费下载链接】jasna Video restoration tool 项目地址: https://gitcode.com/GitHub_Trending/ja/jasna
Jasna 是一个开源的 GPU 视频修复桌面工具,内置 GU… · 2026/11/4 19:07:30
IINA:macOS 上的免费 mpv 播放器,零配置搞定字幕与播放 IINA:macOS 上的免费 mpv 播放器,零配置搞定字幕与播放 【免费下载链接】iina The modern video player for macOS. 项目地址: https://gitcode.com/gh_mirrors/iin/iina
QuickTime 对着一堆花屏的 MKV 无计可施,字幕又总比画面慢半拍… · 2026/11/4 19:07:30
浏览器资源嗅探是怎么工作的:一条 M3U8 请求在 Cat-Catch 里的六道关卡 浏览器资源嗅探是怎么工作的:一条 M3U8 请求在 Cat-Catch 里的六道关卡 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch
猫抓 Cat-Catch… · 2026/11/4 19:07:30
大模型算法八股 一、深度学习与Pytorch(一)神经网络与训练过程输出:线性组合-加入偏置-激活函数对于第一次正向传播,权重的值将随机初始化。sigmoid:输出(0,1)之间,输入值过大或过小梯度消失&#x… · 2026/11/4 19:50:06
SSE 流式输出:数据块边界、语义边界与状态解析 一、SSE 的基本概念与运行机制SSE(Server-Sent Events,服务器发送事件)是一种基于 HTTP 的服务器向客户端持续推送事件的通信机制。它使用 text/event-stream 作为响应的媒体类型,允许服务端在一个持续打开的 HTTP 响应中依次发送… · 2026/11/4 19:48:04
2026 建筑知识图谱选型:从“能查规范“到“能跑闭环“的四层能力阶梯 引言:为什么很多建筑AI项目验收后就沉寂了2024 年全国建筑业总产值达到 32 万亿元,行业体量巨大、链条漫长、信息天然碎片化。智能建造推进至今,多数企业已经上线了各类管理系统,但一线人员仍然频繁遇到这样的困境:设计… · 2026/11/4 19:48:04
从零开始的C语言生活----------变量,分支与循环 1.类型创建变量,运算中的第一缕分支在C语言中,变量的意思十分容易理解,就是变化的量。之前我们学习了类型,那么,类型是做什么的呢?类型就像是月饼的模具侵删像int,char,double之类的… · 2026/11/4 19:48:04
万亿团餐走到数字化拐点-2026订餐领域最受欢迎的小程序-优八群报名 一、市场背景:万亿团餐走到数字化拐点,工具供给却仍卡在“接龙”阶段订餐管理从来不是一个“小需求”。它背后站着的,是一个以万亿计、且仍在持续扩容的团餐市场。艾媒咨询数据显示,中国团餐市场规模已从2016年的0.90万亿元攀升至… · 2026/11/4 19:48:04
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
AI辅助技术栈评估:提升研发决策效率60% 1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17
从生成Token到直接决策:Jev如何重塑AI Agent工程实践 1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17
32G统一内存跑大模型:内存账、TPS实测与端云分流 想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38