性能优化的综合策略与技巧

引言

在当今快速发展的互联网时代,用户体验已成为衡量一个网站或应用成功与否的关键因素。性能优化,作为提升用户体验的重要手段,对于确保用户能够快速、流畅地访问和使用在线服务起着至关重要的作用。本文旨在提供一个全面的性能优化方案,从评估性能指标开始,到设定合理的目标,再到实施有效的优化方法,我们将探讨如何系统地提升网站的性能,确保用户能够享受到更加迅速和稳定的在线体验。

实施阶段划分

性能优化是提升用户体验和网站效率的重要环节,它通常分为三个阶段:评估指标、设置目标、优化方法。在实际操作中,很多开发者可能会忽略前两个阶段,而直接着手于优化手段的选择和应用。

然而,这样的做法可能会导致优化工作不全面,甚至无效。本文将详细介绍如何系统地进行性能优化,从评估指标开始,到设置合理的目标,再到采用有效的优化方法,全面提高网站性能。

1. 评估性能指标

性能优化是一个很大的话题, 其影响因素也很多, 设备、浏览器、协议、网络、延迟都会造成性能明显的变化。所以考虑的因素也很多, 这就需要我们设计一个完善的性能指标, 需要考虑到 CDN,缓存,代理,负载均衡,服务器等。

  • 首先,根据用户实际情况和竞争对手的性能,结合代表设备的性能,制定初步的性能指标。

  • 其次,根据业务场景制定合适的指标。指标通常分为以下几类:

    • 基于数量的指标:衡量请求数量、权重和性能评分,适用于长期监控和告警,但对理解用户体验帮助有限。
    • 里程碑式指标:如首位字节时间(Time To First Byte)、首次可交互时间(Time To Interactive),对用户体验至关重要。
    • 渲染指标:如渲染开始时间(Start Render)和速度指数(Speed Index),有助于检测和调整渲染性能。
    • 自定义指标:衡量特定用户体验,如Twitter的首次发推时间(Time To First Tweet)。

为了构建完整的性能画像,我们可以在上述类型中选择一些关键指标,如首次有效绘制(First Meaningful Paint, FMP)、首次可交互时间(Time To Interactive, TTI)、首次输入延迟(First Input Delay, FID)、CPU耗时、速度指数(Speed Index)和自定义指标。

2. 设置合理的目标

性能目标的设定应基于业务需求和用户期望。以下是一些常见的性能目标:

  • 100ms响应时间,60fps动画流畅度。
  • 速度指数小于1250,首次可交互时间小于5秒,关键文件大小小于170kb(压缩后,压缩前不超过0.7mb)。
  • HTTP请求资源数不超过6个,HTTP/2请求资源数不超过20个。
  • 首屏代码覆盖率大于等于90%。

3. 优化方法

采用PRPL模式和Application Shell架构

PRPL模式

  • P: Push(or preload) the most important resources. 使用 preload 预加载关键资源。

  • R: render the initial route as soon as possible. 提高 FP 速度的方法之一可以使用内联的方式嵌入关键 js/css 资源, 使用 async 异步加载 js 资源。 或者使用服务端渲染。 但是这两种方式都有缺点, 内联会导致代码维护困难, 服务端渲染会影响 TTI 指标。

  • P: Pre-cache remaining assets. 对静态资源进行预缓存, 可以使用 service-worker。

  • L: Lazy load other routes and non-critical assets. 使用合理的拆包策略,将所有类型资源拆分, 拆分后可以 preload 重要的资源。 对非关键图片进行懒加载。

Application Shell 架构

  • 一个 application shell 是支持用户界面的最小HTML、CSS和JavaScript。 其特点在于加载较快、可以被缓存、动态显示内容。
  • Application Shell 的核心在于使用 service-worker 对 shell(外壳) 进行缓存,对于内容使用请求等动态展示。
  • 在首次访问时为了尽快的展示内容(首次渲染),对首次渲染需要的 css 使用内联的方式, 对于外联的 css 进行异步加载可以使用 js 或者 RFA , js 全部进行异步加载。

框架选择

框架的选择应基于项目需求。对于简单业务,使用原生JS或jQuery可能更为合适,可以减少React、Vue、Angular等框架带来的JS文件大小,从而提升首次可交互时间。同时,Vue和Preact在首次内容渲染时间上表现最佳,其次是React。

接口请求的优化

使用REST规范定义接口,并考虑使用GraphQL减少数据浪费。GraphQL允许更精确地请求所需数据,减少不必要的数据传输。

选择合适的 CDN

根据动态数据量选择合适的CDN,将内容推送到CDN并提供静态版本,避免数据库请求。

资源优化

使用 Brotli 或 Zopfli 来对纯文本进行压缩

  • Brotli 一种开源的无损数据格式,现已被所有现代浏览器所支持。因为它比较依赖配置,所以这种压缩可能会(非常)慢,但较慢的压缩意味着更高的压缩率。不过它解压速度很快。 对于动态压缩, 需要考虑其压缩资源所耗费的时间选择合适的压缩级别。 但是对于静态压缩, 首选最高级别的压缩。
  • 你可以考虑使用将数据编码为 Deflate、Gzip 和 Zlib 格式的 Zopfli 的压缩算法。任何普通的 Gzip 压缩资源都可以通过 Zopfli 改进的 Deflate 编码达到比 Zlib 的最大压缩率小 3% 到 8%的文件大小。
  • 动态压缩是即时进行的。用户发出请求,内容被压缩(当用户等待时),压缩后的内容被提供。
  • 静态压缩是指在用户请求之前将资产压缩到磁盘上。当用户请求资产时,不会发生压缩。预压缩资产仅通过磁盘提供。

响应式图片和 webp/AVIF 和图片优化

  • 尽量使用带有 img标签的 srcset、sizes 属性的响应式图片属性和 <picture> 元素。
  • WebP 图像文件大小等价于 Guetzli 和 Zopfli,但它并不支持像 JPEG 这样的渐进式渲染。所以尽管 WebP 图像在网络中的传输速度更快, 但是其兼容不够好, 而且渲染速度较慢, 需要结合场景来使用。
  • AVIF 是比 WebP 还要新的一种格式,它支持全分辨率的10位和12位颜色,所生成的图像比其他已知格式小10倍,同样他的缺点也是兼容性支持。
  • 确保 JPGE 是渐进加载且经过压缩的。

Web 字体

  • Web 字体首选系统自带的字体。
  • 对于自定义的 web font 进行压缩, 因为 unicode 编码里面肯定会有很多空的编码。
  • 根据场景使用 preload。

构建优化

降低 js 的解析成本

js 有一个解析成本, 其相关因素有 js 的大小、硬件的差异。 而仅由 js 大小引起性能问题的情况相对少见, 反而是由于硬件的原因会造成解析和执行的时间有较大的差异。

为了减少 js 的解析成本,在构建项目时我们可以借助一些工具来减少 js 的体积。如: webpack-bundle-analyzer, webpack size-plugin 等。 在开发时我们也可以借助一些工具来分析引入的依赖的大小,如: import cost for vscode。

更有效的方法是避免解析成本, 如 Ember 推出的二进制模板,或者考虑 wasm。

我们需要了解, 虽然 js 的大小很重要, 但是随着 js 体积的增大, 解析和编译时间不一定线性增加。

tree shaking, scope hoisting, code splitting

  • 使用 tree shaking 清理无用的代码。
  • 使用 scope hoisting 减少 js 体积。
  • 使用 code splitting 分隔 bundle , 按需加载。
  • 考虑使用 preload-webpack-plugin 预加载 js 。

web worker

为了减少 TTI , 可以考虑将高耗时的 js 放到 web worker 或者使用 service worker 缓存。

AoT(ahead of time)

考虑使用 AoT(angular) 编译器将一些客户端渲染放到服务器上, 从而快速输出可用结果。

其他的编译器还有 JIT (just-in-time) 即时编译器。

仅将遗留代码提供给旧版浏览器

设置两个构建, 一个使用 es6, 一个使用 es5。 由于现代浏览器对于 es6 的支持较好, 我们可以使用 babel 转义目标浏览器所不支持的特性。使用 script type='module' 让支持 es 模块的浏览器加载 es6 的构建。可以结合 link rel="modulepreload" 使用。 对于老浏览器使用 script nomodule 加载 es5 构建。

modulepreload可以预加载模块及其依赖,提高带宽使用率。

增量解耦

对于一些老项目, 可以使用增量解耦的方式淘汰依赖,如 jquery 等。 可以参考 github jquery的淘汰。 主要方式:

  • 检测每行代码 jquery 的比例,确保该比例是下降的。
  • 使用 eslint 的方式警告开发者不要使用 jquery 相关的 api。
  • 当检测到新增代码中使用了 jquery 特性时, 指定构建失败。

持续监控性能

  • 防止业务变更,代码变动导致性能波动,我们可以对项目进行持续监控。
  • 我们可以借助一些可持续监控工具来描述性能画像, 甚至可以添加自定义指标。例如 travis ci 结合 lighthhouse 可以很方便的获取到当前网页的性能。

其他优化

升级成 http 2.0

资源提示

preload

使用 <link rel="preload" href="" as=""> 可以用来预加载指定资源。 preload 用来预加载当前页面中重要的资源, 通过 as 属性标记当前资源的类型, 浏览器识别可以对加载的资源定义优先级。 当前页面跳转后, preload 资源会中断加载。

prefetch

prefetch 是一个低优先级的资源提示,允许浏览器在后台(空闲时)获取将来可能用得到的资源,并且将他们存储在浏览器的缓存中。

pretetch 针对于下一个页面需要预加载的资源。

prerender

与 prefetch 类似, 都是针对下一个页面的内容, 但是 prerender 会在后台把页面渲染出来, 使用不当容易造成资源浪费。 对于有 post、put等ajax 请求, video,audio标签等页面不会预渲染。

preconnect

preconnect 预先完成 DNS 解析 + TLS 协商 + CP 握手。 preconnect 是个有效而且克制的资源优化方法,它不仅可以优化页面并且可以防止资源利用的浪费。 常用于对 cdn 与预连接。

dns-prefetch

dns 查找是一个耗时的过程, 使用 <link rel="dns-prefetch" href=""> 可以用来预解析当前页面可能跳转的域名。

总结

性能优化是一个系统工程,需要从评估指标、设定目标到采用多种优化手段全面进行。通过本文介绍的方法,可以有效地提升网站性能,改善用户体验。记住,性能优化是一个持续的过程,需要不断地评估、调整和优化。

参考及引用资源:

相关推荐
氢灵子2 分钟前
Canvas 变换和离屏 Canvas 变换
前端·javascript·canvas
GISer_Jing9 分钟前
Axios面试常见问题详解
前端·javascript·面试
库库林_沙琪马11 分钟前
深入理解 @JsonGetter:精准掌控前端返回数据格式!
java·前端
CRPER26 分钟前
告别繁琐配置:一个现代化的 TypeScript 库开发模板,让你高效启动项目!
前端·typescript·node.js
Embrace39 分钟前
NextAuth实现Google登录报错问题
前端
小海编码日记41 分钟前
Geadle,Gradle插件,Android Studio and sdk版本对应关系
前端
粤M温同学1 小时前
Web前端基础之HTML
前端·html
love530love1 小时前
是否需要预先安装 CUDA Toolkit?——按使用场景分级推荐及进阶说明
linux·运维·前端·人工智能·windows·后端·nlp
国科安芯1 小时前
【AS32系列MCU调试教程】性能优化:Eclipse环境下AS32芯片调试效率提升
java·性能优化·eclipse
泯泷2 小时前
「译」为 Rust 及所有语言优化 WebAssembly
前端·后端·rust