前端青训营笔记 提升JavaScript性能的实战经验 | 豆包MarsCode AI刷题

28 阅读4分钟

性能优化与调试技巧:提升JavaScript性能的实战经验

引言

在现代前端开发中,性能优化已成为提升用户体验的关键因素。性能的好坏直接影响页面的加载速度、响应能力以及用户留存率。作为开发者,我们可以通过优化JavaScript代码减少性能瓶颈。本笔记将从减少 重绘和重排、使用 节流和防抖 技术,以及借助 性能分析工具 三个方面探讨优化技巧,并分享一些我的主观见解与经验。


1. 减少重绘和重排

概念解析

  • 重绘 (Repaint) :当页面样式发生变化但不影响布局时,浏览器会重新绘制元素,例如更改背景颜色。
  • 重排 (Reflow) :当页面的布局或几何属性(如宽高、位置)发生变化时,浏览器需要重新计算布局,这比重绘更耗时。

主观思考:在我的开发实践中,重排是页面卡顿的主要原因,特别是在处理大量 DOM 操作时,忽视这一点可能会导致性能灾难。因此,减少重排和重绘是优化的第一步。

优化策略

  1. 避免频繁操作 DOM

    • 尽量批量更新 DOM,减少操作次数。例如,将多次 innerHTML 更新合并到一次。
    // 不推荐
    const list = document.getElementById('list');
    list.innerHTML += '<li>Item 1</li>';
    list.innerHTML += '<li>Item 2</li>';
    
    // 推荐
    let content = '';
    content += '<li>Item 1</li>';
    content += '<li>Item 2</li>';
    list.innerHTML = content;
    
  2. 减少样式查询

    • 访问会触发重排的属性(如 offsetHeight, scrollTop)时,浏览器可能强制刷新布局。避免在循环中频繁访问这些属性。
    // 不推荐
    for (let i = 0; i < items.length; i++) {
        let height = items[i].offsetHeight; // 每次都会触发重排
    }
    
    // 推荐
    const height = container.offsetHeight; // 缓存值
    for (let i = 0; i < items.length; i++) {
        console.log(height);
    }
    
  3. 使用 CSS 动画替代 JavaScript 动画

    /* 使用 CSS 动画 */
    @keyframes fadeIn {
        from { opacity: 0; }
        to { opacity: 1; }
    }
    
    .fade {
        animation: fadeIn 1s ease-in-out;
    }
    

2. 使用节流和防抖技术

概念解析

  • 节流 (Throttle) :控制事件触发的频率,例如规定一段时间内只允许执行一次操作。
  • 防抖 (Debounce) :在事件触发后延迟执行,如果在延迟期间事件再次触发,则重新计时。

主观思考:我常用节流和防抖来优化滚动、输入框等高频事件,尤其是在开发数据表格和动态表单时,合理使用这些技术能够显著减少性能开销。比如说鼠标移动改变一些数值,等到鼠标停止后再更新,而不是onmousemove事件执行时一直改变数值,这样会减少系统的性能开销。

实现与使用

  1. 节流实现

    function throttle(fn, delay) {
        let lastCall = 0;
        return function (...args) {
            const now = new Date().getTime();
            if (now - lastCall > delay) {
                lastCall = now;
                fn(...args);
            }
        };
    }
    
    window.addEventListener('resize', throttle(() => {
        console.log('Resized!');
    }, 200));
    
  2. 防抖实现

    function debounce(fn, delay) {
        let timer = null;
        return function (...args) {
            clearTimeout(timer);
            timer = setTimeout(() => fn(...args), delay);
        };
    }
    
    document.getElementById('search').addEventListener('input', debounce(() => {
        console.log('Searching...');
    }, 300));
    

主观心得:节流更适合固定时间间隔执行的任务,比如窗口大小变化事件;防抖则更适合用户停止操作后的任务,比如输入框实时搜索。这里涉及到函数的闭包,开始在实践的时候花式有点难以去理解的。


3. 借助性能分析工具

性能优化离不开性能监控和调试工具。我常用以下工具来分析问题并验证优化效果:

Chrome DevTools

-   **Performance** 面板:记录页面性能指标,定位重绘和重排的来源。
-   **Lighthouse**:生成性能评分报告。

主观经验:通过使用 Chrome DevTools 的 TimelineCall Tree,我能够快速发现性能瓶颈,比如哪些函数耗时过多,哪些样式改动触发了重排等。希望以后可以在学习时间中学习和了解到更多的性能分析工具,以便我可以更加高效的开发出好的系统。


示例:优化滚动性能

以下是一个优化页面滚动事件性能的综合示例:

// 滚动事件:使用节流 + 减少 DOM 查询
const header = document.querySelector('header');

window.addEventListener('scroll', throttle(() => {
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;

    // 缓存 DOM 查询结果
    if (scrollTop > 100) {
        header.classList.add('hidden');
    } else {
        header.classList.remove('hidden');
    }
}, 200));

总结

通过减少重绘和重排、使用节流和防抖技术,以及借助性能分析工具,我们可以系统性地优化 JavaScript 性能。性能优化不仅仅是技术手段的叠加,更是开发者对代码逻辑和用户需求的深刻理解。

主观感悟:在优化过程中,我发现一个小细节的调整可能带来显著的性能提升。比如,将频繁的 DOM 操作放入内存中批量处理,或者用更高效的数据结构代替繁琐的数组操作。性能优化不仅是对代码的优化,更是对编程思维的提升。