7 个隐藏的 JavaScript 性能瓶颈

缓慢的 Web 应用很少是因为算法差而失败。它们失败的原因在于你的代码与浏览器交互的方式。

我对 300 多个生产环境的应用进行了性能分析。我发现 73% 的性能问题都源于以下 7 个方面。

  1. 布局抖动 (Layout thrashing) 当你读取一个布局属性,然后紧接着向 DOM 写入数据时,就会发生这种情况。这会迫使浏览器多次重新计算布局。 • 影响:渲染速度变慢 40-60%。 • 修复方法:先批量进行所有的读取操作。然后使用 requestAnimationFrame 批量进行所有的写入操作。

  2. 无限制的事件监听器 (Unbounded event listeners) 添加了监听器却不移除会导致内存泄漏。这是单页应用中的一个主要问题。 • 影响:每小时内存增长 15-30%。 • 修复方法:使用 AbortController 在组件卸载时清理监听器。

  3. 循环中的同步 DOM 读取 (Synchronous DOM reads in loops) 在一个同时向 DOM 写入数据的循环内部读取 offsetWidth 等属性,会导致不断的重排 (reflow)。 • 影响:20-40% 的掉帧。 • 修复方法:在循环开始前,将布局值缓存到变量中。

  4. 缺少 requestAnimationFrame 批量处理 (Missing requestAnimationFrame batching) 在滚动或调整大小 (resize) 事件中直接修改 DOM 会触发过于频繁的操作。 • 影响:滚动期间出现 10-25% 的卡顿 (jank)。 • 修复方法:将滚动处理函数包装在 requestAnimationFrame 中,以与绘制周期同步。

  5. 大型 JSON.parse 调用 (Large JSON.parse calls) 解析巨大的 JSON 文件会阻塞主线程,从而导致输入延迟。 • 影响:每次调用导致 50-200ms 的冻结。 • 修复方法:使用 Web Workers 在主线程之外解析数据。

  6. 复杂的 CSS 选择器匹配 (Complex CSS selector matching) 深层嵌套或复杂的选择器会减慢样式重新计算的速度。 • 影响:增加 5-15% 的样式计算时间。 • 修复方法:简化 CSS 结构并使用更扁平的选择器。

  7. 重复的 bundle 分块 (Duplicate bundle chunks) 未经优化的 bundle 会浪费带宽。 • 影响:浪费 100-500KB 的传输量。 • 修复方法:使用 webpack-bundle-analyzer 等工具来查找并移除重复代码。

如何衡量你的进度: • 打开 Chrome DevTools 并进入 Performance 标签页。 • 录制一段 5 秒钟的会话。 • 在 Main 火焰图 (flame chart) 中查找长任务 (long tasks)。 • 应用一项修复,然后对比 Rendering 和 Painting 时间。

专注于这些领域以提高你的 Core Web Vitals 分数。

来源:https://dev.to/kui_luo/how-to-find-and-fix-7-hidden-performance-bottlenecks-in-your-javascript-code-ek5