V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yesvods
V2EX  ›  程序员

极致 Web 性能 —— SPA 性能指南

  •  
  •   yesvods ·
    yesvods · 2018-02-12 12:29:38 +08:00 · 3245 次点击
    这是一个创建于 2236 天前的主题,其中的信息可能已经有所发展或是发生改变。

    作者:Jogis

    原文链接: https://github.com/yesvods/Blog/issues/14

    转载请注明原文链接以及作者信息

    前言

    前端框架时代,为开发体验、效率与页面性能带来,非常大的革命。大家纷纷拿起一系列打包工具(webpack/parcel etc.),配合一系列加载器快速搭建起一个 SPA 页面。

    SPA 应用带来的好处非常明显;

    • 提升页面切换体验
    • 降低切换时间
    • 易于部署&前后端分离

    但是也带来一系列性能问题:

    • 初始加载脚本较大
    • 首屏空白时间较长
    • 页面返回时,数据被动重新拉取

    这些问题是使用 SPA 模式不可避免的,通过了解 SPA 加载运行过程,可以逐渐看清楚引起性能问题的根本原因,通过精细化应用加载,来解决这些问题。

    SPA 之殇

    愈发发福

    比起一般的简单页面,SPA 最大的问题,就是在初始化之时引入大量框架方案脚本,这导致脚本体积随着项目发展体积愈发增大。

    不仅仅是体积

    很多人会关注脚本的加载体积,通过一系列方案来提升缓存命中率,减少脚本请求次数。在网络环境较差的移动端,尽量减少请求时间意义很大。

    但这不是银弹,移动设备对脚本的解析、编译、执行性能较差(脚本加载参考《图说舌尖上的脚本》),即便可以完全利用缓存,执行时间也是性能一大瓶颈。

    Keep SPA Fit

    性能优化原则:贫则独善其身,富则兼济天下。

    如何维护一个大型 SPA ?

    随着项目不断发展,页面不断增加,源源不断的第三方组件&工具库加入到Bundle里面,良好的 SPA 架构可以保证大型 SPA 项目依旧保持极致的性能与体验。下面介绍一个优秀性能&体验 SPA 具备的特性:

    性能优化

    1. 快速启动 —— 极大提升加载速度( important )

    快速启动应用,并行发起 Bundle 加载&拉取初始数据。相信大家已经发现了,SPA 初始化时候,不得不等待 bundle 返回并执行后,才会发起数据加载。

    由于在移动设备上(即便有缓存) bundle 加载极为耗时,我们可以充分利用这段时间将数据进行预加载。这项特性,使得后面的优化起到更加明显的效果。

    如下示例代码:

    // app.js
    Promise.all([load('bundle'), load('data')])
    

    2. 根据路由拆分 —— 减少初始加载体积

    利用异步加载方式,在路由注册时提供异步拉取组件的方法,仅在需要进入对应路由时,对应组件才会被加载进来。

    route({
      Home: () => import('@/coms/home'),
      About: () => import('@/coms/about')
    })
    

    3. 独立打包异步组件公共 Bundle —— 提高复用性&缓存命中率

    HomeAbout等路由里面,可能公用一套 UI 组件,若不将异步加载公用组件统一打包,每次加载 路由时,都会额外加载一套 UI 组件。通过将公用组件提取打包成Vendor,可以减少下次进入路由加载体积与时间。

    BTW:在webpack < 4时,依旧需要手动维护异步加载组件公用组件。webpack4提供更丰富的异步组件抽离方案

    4. 组件预加载 —— 减少页面切换时间

    当首屏加载完毕后,设备&网络处于空闲状态,可以对其他路由组件进行预加载,以便提升页面切换性能。

    预加载是一个非常繁琐的过程,我们可以设计一个极小启动器,在页面渲染后快速预加载后续组件:

    // 所有包含 Page 的路由组件均会被预加载
    boostraper.loadMatch('Page')
    

    5. 使用 ESM 语法 —— 按需打包工具库,降低 Bundle 体积

    webpack4在 ESM tree shaking上做了极大优化,使得在引用工具库时候真正做到"按需打包",这要求无论是自己开发的工具库,抑或使用第三方工具库,打包&使用 ESM 版本非常必要。

    6. 配合 PWA 使用,口感更佳 —— 降低首屏渲染时间,极大提升体验

    根据 PWA 缓存策略,可以将访问的页面index.html缓存起来,下次打开时候优先利用缓存,再发起请求更新缓存。这使得 SPA 应用几乎不需要额外时间便可加载应用首屏文档流。

    体验优化

    1. 构建你的极简Skeleton Page

    SPA 首屏加载面临较长时间白屏,骨架图是一个完美的"缓兵之计"。在谷歌研究员的文章 中有提到,骨架图对用户体验有极大的提升:

    • 快速展示
      • 配合 PWA 首屏缓存,骨架图可实现瞬间加载&展示,首屏视觉上有冲击性地提升
    • 稳定加载
      • 消除页面初始加载因多次重绘&资源加载导致的"抖动"

    需要注意的是,骨架图应尽量保持足够小巧与简单,以确保不会严重影响页面后续加载。

    2. 页面切换 Loading

    无论如何优化性能加载,在页面切换时候依旧需要获取页面数据,若处理不好,可能会在数据返回前有短暂的不友好"空白"。通过以下方式可以很好处理这个问题:

    • 友好的切换前 Loading
      • 在确保组件&数据加载完毕前,可保证页面可交互性,减少用户阻塞感
    • 转场动画
      • 在大多数原生应用,转场动画属于标配
      • 即时组件&数据已经完全加载,在切换至新页面瞬间,依旧需要页面渲染时间,这段时间可能导致页面短暂空白或者"视觉阻塞"
      • 通过转场动画时间,可以很好地缓解这个问题,大多数页面保证在转场动画完毕之后依然渲染完毕

    最后

    除了上述提到的 SPA 优化方案,Web 性能基础也是必备的基石(如域名收敛、合理文档结构)。性能优化本质是一个页面精细化监控运营的过程,也要求我们对 Web 加载的过程与逻辑有更多的思考与理解。

    7 条回复    2018-02-13 10:35:12 +08:00
    KIDJourney
        1
    KIDJourney  
       2018-02-12 13:02:55 +08:00
    全文转载?
    Evaz
        2
    Evaz  
       2018-02-12 14:24:11 +08:00
    @KIDJourney 诶,不是一个人吗?
    sqbing
        3
    sqbing  
       2018-02-12 15:08:34 +08:00
    看了半天才知道 SPA 是 Single Page App 吗?
    xiamx
        4
    xiamx  
       2018-02-12 23:34:59 +08:00
    全文转载? +1
    meszyouh
        5
    meszyouh  
       2018-02-13 10:18:59 +08:00
    说来说去就那几样,没意思。
    spark
        6
    spark  
       2018-02-13 10:26:14 +08:00
    一点干货没有,还到处转发
    iRiven
        7
    iRiven  
       2018-02-13 10:35:12 +08:00 via Android
    然而事实是加载 Google font 时卡住了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1143 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 18:35 · PVG 02:35 · LAX 11:35 · JFK 14:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.