如何优化前端页面加载性能

163 阅读4分钟

一、  相关指标

1.  LCP (Largest Contentful Paint)

指网页从 0 到 1 渲染完成,过程中网页上最大内容元素出现的时间点。

相关场景: 从其他系统跳进当前系统; 刷新浏览器当前系统页面。

2.  LCPS(Largest Contentful Paint -> Spa Page Load)

指网页路由变化后,在不新开浏览器 TAB 的前提下,新加载出来的网页上最大元素出现的时间点。

相关场景:① 点击系统主菜单切换系统页面;②从列表点击跳进详情页。

二、  影响前端页面性能因素

1.  网络资源加载

1.  减少 HTTP 请求(尽量并发,减少阻塞)(下文的3.5解决for循环多次调用接口问题)

2.  使用浏览器缓存

3.  目前静态资源已经采用CDN,基座相关资源json文件已经做了预加载

4.  资源异步加载

5.  减少和优化图片加载

6.  Lazy Loading(懒加载)

2.  前端代码优化

1.  请求响应数据处理方式

2.  降低函数的时间复杂度,减少js复杂计算逻辑

3.  组件优化

3.  渲染性能优化

1.  减少重排和重绘:降低渲染压力

2.  合并多个 DOM 操作,使用文档片段或隐藏元素后进行批量 DOM 更新,尽量避免频繁的 DOM 操作。

3.  尽量减少和合并样式修改,利用 CSS 类来替换内联样式修改。

4.  减少 DOM 元素数量:尽量减少页面上的 DOM 元素数量,复杂的 DOM 结构会影响渲染性能。

4.  优化操作措施

1.  存在无依赖接口时序的请求,没有进行并发请求,多个接口串行,可以用 init-time-analysis 来分析

2.  for循环批量调用多次接口 -- 先组合参数,然后再批量一次性请求,然后进行数据处理

``优化前:

  // 获取单条规则
  *getSingleRule(item) {
    const params = _.pick(item, ['designCode', 'planOnSaleAt']);
    
    if (item.developType === 9) {
      params.backTime = item.backTime;
    }

    const { info, code, msg } = yield rule(params);
    
    if (code === '0') {
      this.state.list = this.state.list.map(n => ({
        ...n,
        rule: n.designCode === info.designCode ? info : n.rule,
      }));
    } else {
      showMessage(msg);
    }
  },

  // 获取下首单规则
  *getRules(list) {
    for (let i = 0; i < list.length; i++) {
      yield this.getSingleRule(list[i]);
    }
  }
};

优化后:

``


  // 第二段代码:批量获取规则
  *getRules(list) {
    const requests = list.map((item) => {
      const params = _.pick(item, ['designCode', 'planOnSaleAt']);
      if (item.developType === 9) {
        params.backTime = item.backTime;
      }
      // 直接将 rule 函数的调用结果(一个 Promise)放入请求数组中
      return rule(params).then(({ info, code, msg }) => ({
        info, code, msg, item,
      }));
    });

    // 发送请求并等待所有调用完成
    const responses = yield Promise.all(requests);
    let tempThisList = _.cloneDeep(this.state.list);

    responses.forEach(({ info, code, msg }) => {
      if (code === '0') {
        tempThisList = tempThisList?.map(n => ({
          ...n,
          rule: n.designCode === info.designCode ? info : n.rule,
        }));
      } else {
        showMessage(msg);
      }
    });

    // 一次性更新 state 中的 list
    this.state.list = tempThisList;
  }
};

3. 图片采用webp格式 -- 图片体积更小,加载速度更快

4.接口数据缓存

四、  页面性能分析工具

使用 Chrome 的 Performance 工具进行性能分析,捕捉页面加载、渲染和交互的详细性能数据,识别和优化问题。 ,

image.png

2. 资源加载优化

1.  图片资源加载优化:确认返回缩略图字段及使用 WebP 格式。

a.  缩略图使用:在非特殊情况下,小图模式下使用图片的缩略图减少图片加载时间,可以采用imageConvert对图片进行签名转换,使用更小体积的webp格式

b.  懒加载:实现图片的延迟加载,只有在视图内时才加载图片,减少初始页面加载时间。

2.  非首屏展示的组件可以延迟加载,或者点击再加载请求

3. 接口优化

1.  合并接口:与后端沟通合并多个小接口,减少请求数。

2.  接口请求优化:排查接口之间的依赖关系,尽可能实现无依赖接口请求的并行,目前我们各系统域名已全面支持 http2,已不存在请求队列最大请求数6-8个的限制,所以可以多个并行请求,同时非页面初始化请求可以根据具体使用场景放到组件中去请求

3.  数据缓存:重复数据请求使用缓存,减少重复请求。-- 目前wrapper缓存接入了少量页面,计划产出一个能够支持常用配置新的接口的缓存方案,实现增量更新,缓解服务器请求压力,加快前端页面渲染

4. 框架/组件/代码层面优化

1.  去除 ready:减少初始页面加载时不必要的延时。

2.  initLoading:优化页面初始化加载逻辑,确保尽早渲染用户可见内容。

3.  合理使用markStatus:优化框架内部的标记状态和加载逻辑,减少不必要的渲染阻塞。

4.  耗时函数优化:降低函数复杂度

5.  合理的组件设计:避免重复渲染

相关链接:

1.  web.dev/articles/op…

2.  inittime分析

3.  PLM前端 -页面性能优化指南

4.  wrapper缓存