JavaScript 性能重绘和重排、使用节流和防抖|豆包MarsCode AI刷题

66 阅读5分钟

性能优化是开发高效、快速响应的 Web 应用程序的重要方面,尤其是在涉及大量 DOM 操作、事件处理和网络请求时。通过有效的优化,可以显著提升页面加载速度、响应能力和用户体验。以下是一些优化 JavaScript 性能的技巧,包括减少重绘和重排、使用节流和防抖、使用性能分析工具等。

1. 减少 重绘重排

重排(Reflow):

重排是指浏览器重新计算元素的位置和几何信息(例如宽度、高度、位置等),通常发生在 DOM 或 CSS 样式发生变化时。当浏览器进行重排时,可能会导致页面性能急剧下降,尤其是在频繁的 DOM 操作或动画中。

重绘(Repaint):

重绘发生在元素的外观(如颜色、背景等)变化时,浏览器会重新渲染元素,但不涉及位置或几何信息的重新计算。

优化策略
  • 批量 DOM 更新: 当需要多次修改 DOM 时,尽量将所有操作批量执行,避免多次导致浏览器的重排和重绘。

    // 不推荐
    element.style.width = '100px';
    element.style.height = '100px';
    element.style.backgroundColor = 'red';
    
    // 推荐:批量修改
    element.style.cssText = 'width: 100px; height: 100px; background-color: red;';
    
  • 使用 requestAnimationFrame 进行动画requestAnimationFrame 可以帮助浏览器优化动画性能,尤其是在重绘过程中,避免多次强制同步样式计算。

    function animate() {
      element.style.transform = 'translateX(100px)';
      requestAnimationFrame(animate);
    }
    requestAnimationFrame(animate);
    
  • 避免布局频繁的访问: 访问 offsetHeightclientWidthscrollTop 等属性会触发浏览器的同步计算,造成性能问题。在修改元素样式之前,尽量将读取和写入 DOM 分开。

    // 不推荐:访问布局信息后直接修改样式
    const height = element.offsetHeight;
    element.style.height = '200px';
    
    // 推荐:先修改样式,再访问布局信息
    element.style.height = '200px';
    const height = element.offsetHeight;
    

2. 节流(Throttling)与 防抖(Debouncing)

节流

节流是限制某个操作在单位时间内的执行次数。对于频繁触发的事件(如滚动、窗口调整大小等),使用节流可以有效减少事件触发次数,从而提高性能。

// 节流函数
function throttle(fn, delay) {
  let lastTime = 0;
  return function() {
    const now = new Date().getTime();
    if (now - lastTime >= delay) {
      fn();
      lastTime = now;
    }
  };
}

// 使用节流
window.addEventListener('scroll', throttle(() => {
  console.log('滚动事件');
}, 200));

防抖

防抖是指在某个操作触发时,延迟执行操作,直到操作结束一段时间后再执行。如果在延迟期间有新的操作触发,就会重新开始计时。防抖通常用于输入框的即时搜索、按钮点击等。

// 防抖函数
function debounce(fn, delay) {
  let timer;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn();
    }, delay);
  };
}

// 使用防抖
const input = document.querySelector('input');
input.addEventListener('input', debounce(() => {
  console.log('输入框内容变化');
}, 300));

3. 懒加载与延迟加载

  • 懒加载:只有在元素出现在视口内时才加载它,通常用于图片、视频、第三方脚本等。

    <img src="placeholder.jpg" data-src="real-image.jpg" class="lazyload" />
    <script>
      const images = document.querySelectorAll('img.lazyload');
      const loadImage = (image) => {
        image.src = image.getAttribute('data-src');
        image.classList.remove('lazyload');
      };
      
      const lazyLoadImages = () => {
        images.forEach(image => {
          if (image.getBoundingClientRect().top <= window.innerHeight) {
            loadImage(image);
          }
        });
      };
      
      window.addEventListener('scroll', lazyLoadImages);
      lazyLoadImages(); // 初始化时加载可视区域的图片
    </script>
    
  • 延迟加载:延迟加载一些不重要的资源,直到需要时才加载。例如,一些非核心的 JavaScript 文件可以在用户交互后才加载。

4. 使用 Web Workers

Web Workers 允许 JavaScript 在后台线程中执行计算密集型任务,而不会阻塞主线程。对于需要大量计算或处理复杂数据的应用,使用 Web Workers 可以显著提升性能。

// 主线程代码
const worker = new Worker('worker.js');
worker.postMessage('开始计算');

// 监听 worker 返回的数据
worker.onmessage = (event) => {
  console.log(event.data); // 获取计算结果
};
// worker.js
onmessage = function(e) {
  // 执行计算或处理数据
  postMessage('计算完成');
};

5. 性能分析工具

为了准确了解和优化应用的性能,使用性能分析工具非常重要。以下是一些常用的工具:

  • Chrome DevTools: Chrome DevTools 是分析性能最常用的工具之一。你可以通过 Performance 面板分析页面加载、重排、重绘、JavaScript 执行等内容。通过 Network 面板查看资源加载情况,优化网络请求。

    • Performance 面板:查看页面加载和渲染过程的详细情况。
    • Memory 面板:查看内存使用情况,查找内存泄漏。
    • Lighthouse:用于分析页面性能、可访问性、SEO 等,提供性能优化建议。
  • WebPageTest: 一个强大的在线工具,用于分析网页加载时间,性能优化建议,支持不同地区和设备的测试。

  • jsPerf: 用于对比不同的 JavaScript 实现方式和代码优化方法,帮助你选择最优的解决方案。

6. 其他优化技巧

  • 避免使用 eval()eval() 会使 JavaScript 引擎停下优化过程,影响性能。避免在生产环境中使用它。

  • 合并和压缩资源:将多个 JavaScript 和 CSS 文件合并成一个文件,减少 HTTP 请求的次数。同时,使用工具如 Webpack、Terser 等进行文件压缩,减少文件大小。

  • 使用 requestIdleCallback:在浏览器空闲时执行一些非关键任务,避免阻塞主线程。

    requestIdleCallback(() => {
      // 执行低优先级任务
    });
    

小结

优化 JavaScript 性能是一个多方面的工作,包括减少不必要的重排和重绘、合理使用节流和防抖、延迟加载资源、利用 Web Workers、分析性能瓶颈等。结合使用各种优化手段,并借助性能分析工具,你可以显著提升应用的响应速度和用户体验。在开发过程中,始终关注性能优化,尤其是在复杂交互、动画和网络请求等高开销操作时。