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

126 阅读4分钟

如何通过优化JavaScript代码来提高性能?

1.减少重绘和重排

重绘和重排是影响页面性能的重要因素,所以优化这些操作可以显著地提高性能。下面来列举一些减少重绘和重排地优化操作。

  • 合并DOM操作:避免频繁地操作DOM,使用documentFragment或innerHTMl一次性更新多个元素。
  • 减少样式计算的影响:
    • 将样式的改动放到一个操作中。
    • 使用类替代内联样式进行批量更新(class)
  • 避免触发同步布局事件:
    • 在实践过程中要尽量避免读取导致浏览器强制计算布局的属性,比如offsetHeight、scrollTop等,特别是写入DOM后立即读取。
    • 缓存这些属性值,能减少重复计算。
  • 使用CSS动画替代JavaScript动画:CSS动画是通过利用GPU进行加速的,行呢个通常比JavaScript动画要好。

2.节流

  • 一段时间内只允许函数执行一次,即使事件不断触发,也会限制函数的调用频率。
  • 节流在固定时间间隔内忽略掉多次触发,只执行最后一次有效调用。

例如页面滚动,滚动页面时频繁触发scroll事件,节流可以让事件处理逻辑每隔一段时间执行一次。

按钮点击:防止用户快速多次点击按钮而导致重复提交。

function throttle(fn, interval) {
    let lastTime = 0; // 上一次执行的时间戳
    return function(...args) {
        const now = Date.now(); // 当前时间
        if (now - lastTime >= interval) {
            lastTime = now; // 更新上次执行时间
            fn.apply(this, args); // 执行函数
        }
    };
}

// 示例:节流的滚动事件
window.addEventListener('scroll', throttle(() => {
    console.log('滚动事件触发');
}, 200));

特点:

  • 在一定时间间隔内函数只执行一次。
  • 不管事件触发有多频繁,函数的调用是有规律的。

3.防抖

确保回调在一定时间内只执行一次。

一段时间内如果事件不断被触发,函数执行被延迟到最后一次触发事件后的特定时间后。如果在等待的时间内事件再次出发,计时器会重置,重新计时。

例如,在用户停止调整窗口大小后,在执行调整布局的逻辑。

另外一个例子,输入框:用户在输入时,不需要每输入一个字符都向服务器发送请求,而是等用户停止输入一段时间后再发送请求。

function debounce(fn, delay) {
    let timer; // 保存定时器
    return function(...args) {
        const context = this;
        clearTimeout(timer); // 每次触发都清除上一次的定时器
        timer = setTimeout(() => fn.apply(context, args), delay); // 重新设置定时器
    };
}

// 示例:防抖的搜索输入
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce(() => {
    console.log('发送搜索请求');
}, 500));

特点:

  • 在事件停止后一定时间后执行函数。
  • 多次触发时函数只执行一次。
对比项防抖节流
触发条件等到事件触发后的一段时间内没有再次触发时,执行函数。在固定时间间隔内只执行一次函数,忽略中间触发。
使用场景用户操作频繁,希望减少不必要的函数调用,如搜索输入提示。高频触发事件中需要定时执行的操作,如滚动、拖拽等。
触发频率最多触发一次(停止触发后的延迟时间)。固定时间间隔触发一次函数(间隔时间内忽略触发事件)。
适用事件input、resize 等用户停止操作后的逻辑处理。scroll、mousemove等需定时处理的逻辑。
实现复杂度需要使用定时器重置逻辑,稍复杂。时间判断逻辑,较为简单。

4.使用性能分析工具

我们可以借助浏览器开发者共和第三方工具来找性能瓶颈。

  • Chrome开发者工具
    • 使用Performance面板分析页面加载、渲染和脚本执行的时间。
    • 使用Memory面板检测内存泄露和内存使用情况。
    • 等等。。。

5.其他

异步加载与懒加载

  • 异步加载资源:使用async和defer加载
  • 懒加载图片资源:
    • 使用原生loading="lazy"或第三方库(比如lazysizes)实现图片懒加载