C端购物类应用的性能优化实践(一)

如何收集和评估首屏性能优化的效果

针对用户访问的关键路径,比如从首页跳转到列表页、从首页跳转到个人中心、从列表页跳转到商详页等,哪些关键页面需要做首屏优化,确定下来范围。

制定每个页面场景的首屏优化目标,比如打开首页,现阶段在低端机上花了2000ms,只要首屏优化到1000ms内就算达标(低端机容易出现性能问题,高端机在性能问题上的表现不明显)。

测试人员根据关键路径,使用低端机操作页面转场,并进行视频录制,将1秒划分为60帧,即每帧约16.7毫秒(为了方便计算,可以改为每一帧20毫秒)。由于网络等影响因素比较多,每一次录制得出的数据都不一样,测试人员需要重复录制10次,去掉10次中的异常数值后取平均值,该平均值作为本次统计的耗时。

举个例子,视频中在第915帧点击了列表页商品,开始转场跳商详,在第970帧时商详页展示主UI,那么耗时为(970-915)*20=1100ms

另外,测试人员需要在发版前、发版后都进行录制,要求发版前录制主要是为了避免性能问题暴露到生产环境上。

排查工具使用

git

有时候发版前,测试人员跟你说xx页面的性能数据比前一天的上涨了几百毫秒,你可以通过指定目录下的24小时内git commit内容改动,快速定位有性能问题的代码改动。

Performance

可以通过谷歌浏览器的Performance面板录制具体页面的trace,进行分析,记得把cpu降速6x

Memory

可以用来排查内存泄漏,先点击强制进行垃圾回收,然后观察指标是否大幅上升

资源的优化

打包工具的资源分析插件

可以用上述插件进行包体积的分析,做针对性的优化,比如js chunk拆分等。举个常见案例,常量的代码如果和工具方法的代码都写在一个js文件里,常量在多个页面被使用,而工具方法只在一个页面被使用,打包时常量和工具方法被打进一个chunk里,其他页面引用该chunk有多余资源浪费。

资源的预取

<link rel="preload" href="https://xx.com/a.webp" as="image"> preload表示资源的优先级最高,比如可以把首屏加载的图片设置为preload。

<link rel="prefetch" href="https://yy.com/915443.js" as="script"> prefetch表示该资源在当前页面用不到,但是下个页面可能会用到,会等当前其他资源加载好了之后,下载队列空闲,该资源才会被下载缓存起来。比如首页跳转列表页,在首页设置prefetch列表页的主chunk。github.com/GoogleChrom... ,quicklink这个库是跟prefetch有关的。

<link rel="preconnect" href="https://cc.com"> preconnect的作用是提前和目标服务器进行连接,比如提前和图片服务器连接好。

<link rel="dns-prefetch" href="https://dd.com"> dns-prefetch的作用类似preconnect

script async: 解析html时,如果遇到标识为async的script标签,不会阻塞解析HTML的剩余代码,会异步请求加载该js脚本,但是脚本加载完成之后会阻塞停止解析html,立即执行脚本,最后等执行完脚本再继续解析html代码。

script defer: 解析html时,如果遇到标识为defer的script标签,不会阻塞解析HTML的剩余代码,会异步请求加载该js脚本,但是脚本加载完成之后不会立即执行脚本,而是等解析完html代码再执行该js脚本。

图片的优化

图片自动转webp

在首页、列表页等ssr页面,判断设备是否支持webp,将结果写入cookie中,这样做可以在node端读取cookie判断,支持webp的话就进行转换(需要图片服务器同时提供png、webp等格式)

js 复制代码
const isSupportWebp = function () {
  if (typeof window === 'undefined') {
    return false
  }
  const $canvas = document.createElement('canvas')
  const data = $canvas && $canvas.toDataURL('image/webp', 0.5)
  return data.indexOf('data:image/webp') === 0
}

const transformWebp = function (imgUrl) {
  const imgHosts = ['img1.com', 'img2.com']
  const canTransform = imgHosts.some(host => imgUrl.includes(host))
  if (canTransform) {
    return imgUrl.replace(/\.(jpg|jpeg|png)$/, '.webp')
  }
  return imgUrl
}

图片手动预取

比如我们可以在首页空闲时主动预取一些个人中心的图片,当跳到个人中心时图片就是从缓存中读取

js 复制代码
export const preloadImgs = async (imgs = [], timeout = 3000) => {
  return Promise.race([
    new Promise((resolve) => {
      let loadedNum = 0
      const imgLoadHandle = () => {
        loadedNum++
        if(loadedNum === imgs.length) {
          resolve()
        }
      }
      imgs.forEach((src) => {
        const img = new Image()
        img.src = src
        img.onload = imgLoadHandle
        img.onerror = imgLoadHandle
      })
    }),
    new Promise((resolve) => {
      setTimeout(() => {
        resolve()
      }, timeout)
    })
  ])
}

在测试图片的预取是否生效时记得不要开启浏览器Network面板的disable cache,开启了会导致图片缓存不生效。

lazyload

非首屏图片设置lazyload

图片裁切

手机宽度有很多种宽度,ipad设备宽度一般比手机宽度大很多,根据设备宽度获取不同size的图片(图片服务器需要提供不同size的图片),比如375宽度只需要750宽度的图片,不需要获取1366宽度图片,750宽度图片比1366宽度图片小很多。

更多内容看第二篇(第二篇还没写完)

相关推荐
计算机-秋大田几秒前
基于微信小程序的校园失物招领系统设计与实现(LW+源码+讲解)
java·前端·后端·微信小程序·小程序·课程设计
林涧泣10 分钟前
【Uniapp-Vue3】下拉刷新
前端·vue.js·uni-app
浪遏18 分钟前
Langchain.js | Memory | LLM 也有记忆😋😋😋
前端·llm·aigc
luoganttcc1 小时前
华为升腾算子开发(一) helloword
java·前端·华为
九月十九2 小时前
AviatorScript用法
java·服务器·前端
_.Switch3 小时前
Python Web开发:使用FastAPI构建视频流媒体平台
开发语言·前端·python·微服务·架构·fastapi·媒体
菜鸟阿康学习编程3 小时前
JavaWeb 学习笔记 XML 和 Json 篇 | 020
xml·java·前端
索然无味io4 小时前
XML外部实体注入--漏洞利用
xml·前端·笔记·学习·web安全·网络安全·php
ThomasChan1234 小时前
Typescript 多个泛型参数详细解读
前端·javascript·vue.js·typescript·vue·reactjs·js
爱学习的狮王4 小时前
ubuntu18.04安装nvm管理本机node和npm
前端·npm·node.js·nvm