03 性能优化与调试技巧 | 豆包MarsCode AI刷题

52 阅读3分钟

1. 性能优化的核心概念

重绘 (Repaint) 与重排 (Reflow)

  • 重绘:当元素的外观样式(如颜色、背景等)发生变化时,需要重新绘制,但不会影响布局。
  • 重排:当元素的几何属性(如大小、位置等)发生变化时,会触发整个文档的重新布局,开销比重绘更大。

如何避免频繁的重排和重绘

  • 减少 DOM 操作

    • 合并多次操作,使用文档片段(DocumentFragment)。
    • 避免频繁访问 DOM,改为缓存结果。
  • 使用 CSS 合理布局

    • 避免使用动态计算的样式属性(如 offsetHeight 等)引发多次重排。
  • 批量更新样式

    • 使用 classList 一次性添加/删除类,而非逐条修改样式。

实践示例

测试环境准备

1. HTML 结构 在页面中创建一个测试容器元素:
<div id="example" style="height: 200px; overflow: auto; border: 1px solid #000;"></div>
页面效果
  • image.png
2. 测试代码 将两段代码分别封装为可调用的函数:
function inefficientMethod() {
  const element = document.getElementById('example');
  for (let i = 0; i < 1000; i++) {
    element.style.width = `${i}px`; // 频繁修改导致性能低下
  }
}

function efficientMethod() {
  const element = document.getElementById('example');
  const fragment = document.createDocumentFragment();
  for (let i = 0; i < 1000; i++) {
    const div = document.createElement('div');
    div.style.width = `${i}px`;
    fragment.appendChild(div);
  }
  element.appendChild(fragment); // 一次性操作 DOM
}

3. 使用 console.time 测量执行时间
console.time('Inefficient Method');
inefficientMethod();
console.timeEnd('Inefficient Method');

console.time('Efficient Method');
efficientMethod();
console.timeEnd('Efficient Method');

通过 JavaScript 内置的性能计时方法测量代码块的运行时间:
  • image.png
  • 如图在浏览器控制台查看两者的执行时间差异

2. 节流 (Throttle) 与防抖 (Debounce)

节流 (Throttle)

  • 限制一个函数在指定时间内最多执行一次,适用于 连续触发的事件(如滚动、缩放)

实践示例:验证节流功能是否正常工作

测试环境准备

1. 在页面上添加一个滚动区域
<div style="height: 2000px; background: linear-gradient(to bottom, #fff, #ccc);">
  Scroll down to test throttling!
</div>
  • 如图所示:image.png
2. 将节流函数封装为测试场景的一部分:
// 测试用节流函数
function throttle(func, limit) {
  let lastCall = 0;
  return function (...args) {
    const now = Date.now();
    if (now - lastCall >= limit) {
      lastCall = now;
      func.apply(this, args);
    }
  };
}

// 滚动事件测试
let callCount = 0; // 记录调用次数
function logScroll() {
  callCount++;
  console.log('Scroll event triggered:', callCount, 'times');
}

window.addEventListener('scroll', throttle(logScroll, 200));
3. 打开浏览器开发者工具,观察控制台
  • 快速滚动页面,查看日志输出频率是否每隔 200 毫秒触发一次。
  • image.png

防抖 (Debounce)

  • 延迟函数执行,直到事件停止触发一定时间,适用于 用户输入、搜索建议等场景

实践示例:验证防抖功能是否正常工作

测试环境准备

1. 在页面上添加一个输入框
<input id="search" type="text" placeholder="请输入内容,测试防抖效果" />
页面效果
  • image.png
2. 将防抖逻辑与输入框事件结合
// 防抖函数
function debounce(func, delay) {
  let timer;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => func.apply(this, args), delay);
  };
}

// 输入事件绑定
const input = document.getElementById('search');
let callCount = 0; // 用于记录调用次数
input.addEventListener(
  'input',
  debounce(() => {
    callCount++;
    console.log('Debounced input event:', callCount);
  }, 300)
);

3. 交互测试
  • 快速输入内容,观察日志输出是否延迟 300ms。
  • 停止输入后,是否只触发最后一次的事件。
  • image.png

总结与建议

  • 优先解决重绘和重排问题,减少 DOM 操作和不必要的样式计算。
  • 灵活使用节流和防抖,优化高频事件的性能开销。
  • 充分利用 DevTools 和 Lighthouse,定位性能瓶颈并持续改进。
  • 代码优化是一项持续工作,通过工具与最佳实践结合,保持页面性能稳定。

在线工具

  • CodePen 如果有特定优化场景需要探讨或其他问题,随时提问!

参考