JavaScript / TypeScript 易踩坑知识点 —— 性能与内存类
JavaScript / TypeScript 易踩坑知识点 —— 性能与内存类一、循环中频繁操作 DOM问题说明在循环中每次操作 DOM 都会触发浏览器的重排Reflow和重绘Repaint性能极差。踩坑示例// ❌ 每次循环都操作 DOM触发多次重排constlistdocument.getElementById(list)for(leti0;i1000;i){constlidocument.createElement(li)li.textContentItem${i}list.appendChild(li)// 每次 append 都触发重排}// ✅ 方案1DocumentFragment推荐constfragmentdocument.createDocumentFragment()for(leti0;i1000;i){constlidocument.createElement(li)li.textContentItem${i}fragment.appendChild(li)}list.appendChild(fragment)// 只触发一次重排// ✅ 方案2字符串拼接后一次性插入lethtmlfor(leti0;i1000;i){htmlliItem${i}/li}list.innerHTMLhtml// 只触发一次重排性能对比方案重排次数适用场景每次 appendN 次不推荐DocumentFragment1 次推荐类型安全innerHTML 拼接1 次简单场景注意 XSS二、内存泄漏问题说明JavaScript 有垃圾回收机制GC但某些模式会导致僵尸对象无法被回收造成内存泄漏。常见泄漏场景1. 未清理的事件监听器classMyComponent{constructor(){window.addEventListener(resize,this.handleResize)// ❌ 组件销毁时未移除}handleResize(){console.log(window resized)}// ✅ 在组件销毁时移除监听器destroy(){window.removeEventListener(resize,this.handleResize)}}2. 定时器未清除// ❌ 组件销毁后定时器仍在运行useEffect((){consttimersetInterval((){console.log(tick)},1000)// 没有清理函数组件卸载后定时器继续运行},[])// ✅ 返回清理函数useEffect((){consttimersetInterval((){console.log(tick)},1000)return()clearInterval(timer)// 组件卸载时清除定时器},[])3. 闭包引用大对象// ❌ 闭包持有了对大对象的引用导致无法回收functionsetupBigObject(){constbigDatanewArray(1000000).fill(data)returnfunction(){returnbigData.length// 闭包引用了 bigData}}constgettersetupBigObject()// bigData 无法被 GC 回收因为 getter 的闭包仍然引用它// ✅ 避免在闭包中引用不需要的大对象functiongetLength(){constbigDatanewArray(1000000).fill(data)constlenbigData.length// bigData 在函数结束后可以被回收returnlen}4. 数组/集合持续增长// ❌ 数组只增不减内存持续增长constcachenewMap()functionfetchData(id){if(!cache.has(id)){cache.set(id,fetch(/api/data/${id}))}returncache.get(id)}// 随着 id 增多Map 会无限增长// ✅ 设置缓存上限或使用 LRU 策略importLRUCachefromlru-cacheconstcachenewLRUCache({max:100})// 最多缓存 100 条三、防抖与节流问题说明高频事件如scroll、resize、input的回调函数如果不加控制会导致性能问题。防抖Debounce// 防抖在最后一次调用后延迟执行期间再次调用则重新计时functiondebounce(fn:Function,delay:number){lettimer:ReturnTypetypeofsetTimeout|nullnullreturnfunction(...args:any[]){if(timer)clearTimeout(timer)timersetTimeout((){fn.apply(this,args)},delay)}}// 使用搜索框输入时防抖consthandleSearchdebounce((keyword:string){fetch(/api/search?q${keyword}).then(resres.json()).then(datarenderResults(data))},300)inputElement.addEventListener(input,(e){handleSearch((e.targetasHTMLInputElement).value)})节流Throttle// 节流固定时间间隔内只执行一次functionthrottle(fn:Function,interval:number){letlastTime0lettimer:ReturnTypetypeofsetTimeout|nullnullreturnfunction(...args:any[]){constnowDate.now()constremaininginterval-(now-lastTime)if(remaining0){fn.apply(this,args)lastTimenow}elseif(!timer){timersetTimeout((){fn.apply(this,args)timernulllastTimeDate.now()},remaining)}}}// 使用滚动事件节流window.addEventListener(scroll,throttle((){console.log(scroll position:,window.scrollY)},100))防抖 vs 节流对比场景推荐原因搜索框输入防抖用户输完再请求窗口 resize节流持续监听尺寸变化按钮点击防抖防止重复提交滚动加载节流定期检测位置鼠标移动节流降低事件频率四、事件委托问题说明给每个子元素单独绑定事件监听器会消耗大量内存使用事件委托可以在父元素上统一处理。踩坑示例// ❌ 给每个 li 绑定事件1000 个 li 1000 个监听器constitemsdocument.querySelectorAll(li)items.forEach(item{item.addEventListener(click,(){console.log(item.textContent)})})// ✅ 事件委托在父元素上监听通过 event.target 判断constlistdocument.getElementById(list)list.addEventListener(click,(event){consttargetevent.targetasHTMLElementif(target.tagNameLI){console.log(target.textContent)}})Vue/React 中的事件委托!-- Vue 中动态列表 -- template ul clickhandleListClick li v-foritem in items :keyitem.id{{ item.name }}/li /ul /template script setup const handleListClick (event: MouseEvent) { const target event.target as HTMLElement if (target.closest(li)) { const id target.closest(li)?.dataset.id console.log(Clicked item:, id) } } /script五、大数据列表虚拟滚动问题说明渲染大量 DOM 节点如 10000 行表格会导致页面卡顿虚拟滚动只渲染可见区域的节点。原理说明虚拟滚动的核心思想是只渲染视口内可见的 DOM 节点通过计算偏移量来模拟滚动效果。使用第三方库推荐// 推荐使用成熟的虚拟滚动库// vue-virtual-scrollerVue// react-window / react-virtualizedReactimport{List}fromvue-virtual-scroller// 基本用法// 需要指定 itemHeight每行高度和 visibleItems可见区域可显示的最大行数// 库会自动计算并只渲染可视区域内的行手动实现思路// 虚拟滚动核心逻辑functioncalculateVisibleItems(scrollTop:number,containerHeight:number,itemHeight:number,totalItems:number){conststartIndexMath.floor(scrollTop/itemHeight)constendIndexMath.min(startIndexMath.ceil(containerHeight/itemHeight)1,totalItems)return{startIndex,endIndex}}// 用 transform: translateY 模拟滚动位置// 只渲染 startIndex 到 endIndex 之间的数据六、图片与资源优化问题说明大图片和未优化的资源是页面加载慢的主要原因之一。优化策略// 1. 图片懒加载constimagesdocument.querySelectorAll(img[data-src])constimageObservernewIntersectionObserver((entries,observer){entries.forEach(entry{if(entry.isIntersecting){constimgentry.targetasHTMLImageElement img.srcimg.dataset.src||img.removeAttribute(data-src)observer.unobserve(img)}})})images.forEach(imgimageObserver.observe(img))// 2. 图片压缩上传前functioncompressImage(file:File,maxWidth:number800):PromiseBlob{returnnewPromise((resolve){constimgnewImage()img.srcURL.createObjectURL(file)img.onload(){constcanvasdocument.createElement(canvas)constscaleMath.min(1,maxWidth/img.width)canvas.widthimg.width*scale canvas.heightimg.height*scaleconstctxcanvas.getContext(2d)ctx?.drawImage(img,0,0,canvas.width,canvas.height)canvas.toBlob(blobresolve(blob!),image/jpeg,0.8)}})}// 3. 使用 WebP 格式更小的文件体积// picture 标签提供格式降级// picturesource srcsetimage.webp typeimage/webpimg srcimage.jpg/picture七、requestAnimationFrame 替代 setTimeout/setInterval问题说明setTimeout和setInterval的精度不够高且不受页面可见性影响动画场景推荐使用requestAnimationFrame。踩坑示例// ❌ setInterval 做动画精度低且可能掉帧letpos0setInterval((){box.style.leftpospx},16)// 约 60fps但不精确// ✅ requestAnimationFrame 与浏览器刷新率同步functionanimate(){pos1box.style.leftpospxif(pos100){requestAnimationFrame(animate)}}requestAnimationFrame(animate)// ✅ 页面不可见时自动暂停document.addEventListener(visibilitychange,(){if(document.hidden){// 暂停动画}else{// 恢复动画}})总结对照表坑点错误写法正确写法循环操作 DOM每次循环 appendDocumentFragment事件监听器泄漏未移除监听器销毁时 removeEventListener定时器泄漏未清除定时器useEffect 返回清理函数闭包引用大对象闭包持有大对象引用避免在闭包中引用不需要的大对象缓存无限增长Map/Array 只增不减LRU 缓存设置上限高频事件无节流直接绑定 scroll/input防抖/节流每个子元素绑定事件forEach 绑定监听器事件委托大数据列表全渲染渲染 10000 行 DOM虚拟滚动大图片不压缩直接上传原图上传前压缩 WebPsetInterval 做动画setIntervalrequestAnimationFrame

相关新闻

安装Pyside 6

安装Pyside 6

安装Pyside 6一、前言最近的AI Agent编写需要用到界面交互,比如CLI对话机器人,我们只能看到命令行,没法看到交互界面。想到了使用Python写界面,就想到了PyQt和PySide,PySide还没有用过(以前都是用PyQt&…

2026/10/9 5:20:26 阅读更多 →
axure9.0 如何打造一个计时器(带前导零)

axure9.0 如何打造一个计时器(带前导零)

原理:在 Axure 9.0 中制作计时器,核心思路是利用“页面载入时”事件形成一个循环。🕹️ 第一步:创建变量与界面创建全局变量:点击顶部菜单「项目」→「全局变量」。在弹出的窗口中,点击“添加”&#xff0c…

2026/10/9 5:20:26 阅读更多 →
JavaScript运算符全解析:从隐式转换到位运算与避坑指南

JavaScript运算符全解析:从隐式转换到位运算与避坑指南

我在后台系统改一处权限判断时,被新同事反问得很不舒服:“JavaScript运算符不是入门第一课吗?还有什么好讲的?”我把线上事故清单打开给他看:库存数字被隐式转换加成了字符串、默认值用逻辑或结果把 0 和空字符串直接覆…

2026/10/9 5:19:26 阅读更多 →

最新新闻

基于伴随灵敏度分析与肿瘤生长模型的放疗计划优化方法

基于伴随灵敏度分析与肿瘤生长模型的放疗计划优化方法

在肿瘤放疗计划里,我们通常习惯把靶区勾画好、给一个最大耐受的处方剂量,然后按均匀分布的射束照下去。但肿瘤在治疗周期里是不断变化的,细胞增殖速度快慢、对剂量的响应强度,每一天都不一样。如果能让放射治疗计划跟着肿瘤的“实…

2026/10/9 6:25:18 阅读更多 →
单细胞衰老时钟全流程解析:从数据质控到模型训练

单细胞衰老时钟全流程解析:从数据质控到模型训练

单细胞测序技术火了这么多年,数据越攒越多,但绝大多数分析还是停留在“聚类看分群、注释找细胞类型”的层面。直到“衰老时钟”这个概念从表观遗传学延展到单细胞转录组,很多人才意识到,我们完全可以回答一个更刁钻的问题&#xf…

2026/10/9 6:25:18 阅读更多 →
灰狼优化算法GWO从原理到Python实现:参数分析与工程踩坑经验

灰狼优化算法GWO从原理到Python实现:参数分析与工程踩坑经验

灰狼优化算法(GWO算法)这几年的热度,在元启发式算法里算是现象级的。写论文的拿它做对比算法,做工程的拿它做参数寻优,搞机器学习的拿它调超参数,甚至连不少教材都把GWO列进了智能优化算法的必修清单。它能…

2026/10/9 6:25:18 阅读更多 →
OpenRig 实战指南:基于 Node.js + tmux 的本地 AI 工具链搭建

OpenRig 实战指南:基于 Node.js + tmux 的本地 AI 工具链搭建

1. OpenRig 是什么:一个被误读的开源项目名与真实技术现场 OpenRig 这个词在当前中文技术社区里,正经历一场典型的“语义漂移”——它既不是某个广为人知的成熟开源项目,也不是官方发布的工具套件,而更像是一个在开发者私有工作流…

2026/10/9 6:25:17 阅读更多 →
基于SpringBoot+Vue+MyBatis的汽车租赁管理系统设计与实现

基于SpringBoot+Vue+MyBatis的汽车租赁管理系统设计与实现

坦白说,看到标题里“管理系统管理系统”这个重复词的时候,我愣了一下。但做技术这行久了也明白,这类源码发布贴经常是复制标题时手滑。真正让我感兴趣的是后面那串技术组合:SpringBoot Vue MyBatis MySQL。这四个词放在一起&am…

2026/10/9 6:25:17 阅读更多 →
JS对象与BOM协作指南:从类型判断到页面跳转高频实战

JS对象与BOM协作指南:从类型判断到页面跳转高频实战

1. 从 "JS 对象撞上 BOM" 聊起:一次重构翻车现场前段时间我重构一个老项目里的页面跳转逻辑,原本只是想把散落在按钮回调里的 "window.location.href xxx" 抽成一个统一的导航配置对象。改完以后测试同学跑了一圈,反馈说…

2026/10/9 6:24:16 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →