性能优化的目的

提高用户体验,保证用户留存

  • 首屏时间(白屏时间)
  • 首次可交互时间
  • 首次有意义内容渲染时间
  • 卡顿
  • loading 时间

I/O 优化

前端常见 I/O 是网络 I/O

HTTP 协议升级

HTTP 各版本差异

合理利用缓存

  • CDN:内容分发网络,源站内容分发至全国(全球)不同节点
    • CDN 预热:主动从源站推送到 CDN,让用户访问到 CDN 时不用回客户的源站命中
    • CDN 刷新:淘汰 CDN 节点上的旧文件,重新获取文件的新版本
  • 强缓存和协商缓存

只请求当前需要的资源

  • 异步加载:如路由懒加载
  • 懒加载:如图片懒加载
  • polyfill:用来为旧浏览器提供它没有原生支持的较新的功能(API)
    • 打包多份,根据浏览器环境选择合适的 polyfill 包,而不是全部都加载 polyfill

缩减资源体积和请求数量

  • 打包压缩:代码压缩混淆、tree shake
  • gzip:压缩效率极高
  • 图片格式的优化:webp、压缩,根据需求选择合适的分辨率(根据屏幕分辨率展示不同分辨率的图片)
  • 尽量控制 cookie 的大小:每次请求的请求头中都会携带同域下所有的 cookie
  • 雪碧图(HTTP/2 不需要控制请求数量,因为没有 6 个 TCP 连接限制)

时序优化:资源加载顺序

  • JS 的 Promise.all:并行执行异步任务
  • SSR:把打包放到服务端,服务端对共性资源可以缓存,利于 SEO
  • prefetchprerenderpreload资源提示关键词

符合人体工学的设计

添加 loading、骨架屏设计,而不是白屏,降低用户焦虑度

CPU 优化

JS 长任务阻塞页面渲染

JS 执行和页面渲染都在渲染主线程一个线程中执行,JS 占用太长时间超出一帧的时间(16.667 ms),用户就会感知卡顿

解决方法:将长任务打断成多个短任务

// 下一个宏任务再继续运行
function sleep(time) {
  return new Promise(resolve => setTimeout(resolve, time))
}

多线程

使用 Web Worker 创建多线程运行

JS 动画使用 requestAnimationFrame

requestAnimationFrame 每帧调用,保证动画流畅性

任务优先级

符合人体工学,区分任务优先级,优先执行用户关心度和感知度高的任务

开发体验/工具链优化

dev server

  • HotModuleReplacement(HMR,热模块替换):只对修改的模块重新打包编译
  • OneOf:打包时每个文件都会经过所有 loader 处理,虽然因为 test 正则没匹配上,但是都要过一遍,比较慢。实际上只需要匹配一个 loader,剩下的就不匹配了

其他

  • 工程化、自动化
  • 代码热更新
  • TS 代码提示
  • 代码编辑器自动格式化、风格和错误检查