Skip to content

⚠️ Important Notice

This post was last updated on: which was . Please pay attention to its timelines.

PerformanceOptimization 性能优化

谈到性能优化,首先需要有统一的指标作为标准,不然何谈优化呢。

而性能指标,遵循“首次原则”和“持续性原则”。

  • 首次原则:用户首次打开网站或应用时,需要以足够快的速度打开页面。
  • 持续性原则:用户在后续使用网站或应用时,需要流畅的响应。

性能指标

这篇关于性能指标的介绍

性能监控

往往开发时能通过浏览器的devtools面板看到这些性能指标,但是在用户的电脑上我们可看不到,所以需要添加额外的代码来监控性能指标,以性能监控的目的。

前端收集性能数据的方式有很多:

  • performance API
  • PerformanceObserver
  • 第三方库 如web-vitals

当监控到这些性能指标数据后 需要上报到服务器存到数据库中,然后进行分析处理,以达到性能监控的目的。

性能监控往往是在生产环境应用的,开发环境中还是需要手动查看性能指标,以便在开发环境进行性能优化。

开发环境的性能诊断

Chrome DevTools工具

  • Performance面板
  • LightHouse面板

Performance API 埋点

通过手动添加测量性能的代码来检查性能。

注入诊断

在一些页面由于死循环、内存泄漏等原因导致页面卡死时,上面的方式就不生效了,这时可以通过注入诊断的方式来检查性能。

通过babel等工具在构建代码时,往代码块(while函数体、for循环、递归等)中注入标记代码,记录次数,如果大于一定次数,直接throw,防止页面死循环无响应。

优化方法

代码构建时的优化

  • 打包和分包

  • 按需加载

资源优化

  • 代码压缩
  • 图片的优化

网络优化

从发出请求到接收到服务端响应,先后有DNS解析、TCP连接、https的TSL安全连接、数据请求。

  • DNS缓存
  • HTTP缓存
  • CDN分发
  • HTTP2

关于HTTP进化的一些问题

没有长连接之前,一个请求就要一次TCP连接,很耗时。 HTTP1.1引入了长连接,虽然能复用TCP连接了,但是一次只能处理一个请求,就是请求 -> 响应 -> 请求 -> 响应这种模式,上一次请求结束之后才能进行下一次请求。 HTTP2引入了多路复用,通过二进制分帧层以及流的逻辑概念,在一个TCP中可以同时处理多个请求。每个流代表一个请求,每个流都有自己的id进行标识。 HTTP2并没有完全解决TCP阻塞的问题,因为TCP有重传机制,所以某个包丢失会导致重传,这样就会阻塞后面的请求。另外HTTP2只有TCP连接,可能比HTTP1.1阻塞的更加严重。 所以HTTP3基于UDP协议搞了个新的协议QUIC。

应用分发优化

  • PWA
  • ServiceWorker
    • Workbox
  • 微前端:前端代码架构的处理,可以提高巨型项目的响应速度

浏览器渲染相关优化

理解重排Reflow 重绘Repaint,是怎么影响渲染流水线的。

  • 重排Reflow:从layout阶段开始重新走,会重新遍历完整的Layout树计算元素位置和大小。非常耗时。一个元素的位置变动,都需要遍历一整个树。
  • 重绘Repaint:从生成绘制指令开始,重新光栅化、绘制页面。相比来说成本要低一些。

一般而言位置变动都会导致重排,但是translate不会重排,因为是单独的图层,有自己的单独的layer层,走GPU独立渲染。

  • 防抖节流:减少执行次数

  • 虚拟视口:通常长列表或长表格中,具体就是虚拟列表和虚拟表格。只渲染视口及附近的元素,避免全量渲染。

  • 时间切片:requestIdleCallback。比如日志的上报等 最好不要影响主线程,所以可以放在空闲时间来执行上报。

requestAnimationFrame也是的,执行后就会清掉

多线程(Worker线程)

  • webWorker:dedicatedWorker 通过new Worker()创建实例

  • 其他类型的worker

    • SharedWorker:多个浏览器窗口之间共享的脚本。通过new SharedWorker()创建实例
    • ServiceWorker:类似代理服务器,是PWA的关键部分。通过navigator.serviceWorker.register()注册worker。
  • WebAssembly:把其他语言编译成webAssembly程序,放到浏览器中执行,通过给JS程序提供API来调用,避免JS引擎的短板。

V8介绍

  • JIT即时编译:解释器和JIT编译器(两部分:一个转成字节码 一个转成机器码)
  • GC垃圾回收:内存分为两部分,分开用两个垃圾回收器来管理,判断垃圾都是用的可访问性算法,新生代(Scavenge算法 分成两个空间 等执行GC时复制、清除、互换位置)、老生代(分为两个空间 标记出垃圾 然后GC,非垃圾移动到一端 清空另一端)
  • 其他的一些V8优化:隐藏类、缓存、对象属性存储等。

JS特性

为什么堆要慢?

  • 想要读取对象属性,首先要在栈中取到堆的引用地址,然后去堆中遍历找到该地址对应的内存,再去该内存中取到属性,如果是嵌套的对象,还要继续遍历,直到找到属性。

总结

可以看到,前端的性能优化就这个几个大方向:加载、渲染、内存占用、网络、架构设计等。

从TCP/IP四层模型的方向来总结一下性能优化的方向:

  • 应用层主要的优化方向:是前端主要的优化途径
    • 浏览器的加载:主要是和资源优化,比如减少资源体积,减少不必要的资源,利用CDN加快资源到达速度等
    • 浏览器的渲染:通过分析一帧的流程,减少流程的时间 让一帧足够流畅。比如React的时间切片;虚拟表格;避免重排重绘;合成层等等
    • 开发体验的优化:升级构建工具,提高构建打包的速度;
    • HTTP2的头部压缩
    • HTTP缓存:强缓存、协商缓存
  • 传输层的优化方向
    • TCP连接的优化:1.1的长链接 2的多路复用 3的QUIC协议
  • 网络层的优化方向
    • 因为需要IP,所以只有DNS相关的优化前端能控制,比如dns-prefetch。但是DNS的发起是在应用层的,所以是属于应用层的优化。
  • 链路层的优化方向
    • 升级硬件

网络层和链路层 前端基本没有什么优化空间,依赖于基础设施的优化。

上一次更新: