本文由 IMWeb 团队成员 lq 首发。点击阅读原文查看 IMWeb 社区更多精彩文章。
注:本文需要有一定的 PWA 基础
要知道一个东西是什么,我们通常可以从它的名字入手
因此我们看下 PWA 的全称是: Progressive Web App
回答 what 这种问题,重点在于名词,因此 PWA 是一个 APP,一个独立的、增强的、Web 实现的 APP
要达到这样的目的,PWA 提供了一系列的技术 & 标准,如下图所示:
具体每一项技术是什么就不再赘述了,感兴趣的同学自行网上搜索! 下面有一个简单的 demo 可以简单体会一下:
以后我们的 web 站点可以像 app 一样,这难道不是一个令人兴奋的事情吗?
所以 PWA 是值得我们前端开发者一直关注的技术!
按照目前的兼容性和环境来看,大家应用最多的还是 Service Worker,因此接下来我们也是把重点放在 SW 上面
那什么是 Service Worker ?
大家都知道就不卖关子了,其实就是一个 Cache
说到 Cache,就一定会想到性能优化了,请看我们的第二部分
如何利用 Cache 来进行优化?这个基本套路应该无人不知了:
那么首次加载怎么办呢?首次加载是没有缓存资源的,所以会走到线上,所以等于没有任何优化
答案就是 Cache 的第二种常用技巧: precache(预加载)
预加载的意思就是在某个地方或特定时机预先把需要用到的资源加载并缓存
我们的做法如下图所示:
构建的时候,把整个项目用到的资源输出到一个 list 中,然后 inline 到 sw.js 里面
当 sw install 时,就会把这个 list 的资源全部请求并进行缓存
这样做的结果就是,无论用户第一次进入到我们站点的哪个页面,我们都会把整个站点所有的资源都加载回来并缓存
当用户跳转另外一个页面的时候,Cache 里面就有相应的资源了!
这是我们辅导课堂页面接入 sw 之后的首屏优化效果:
除了静态资源之外,我们还能缓存其他的内容吗?
答案肯定是可以的,我们还可以缓存 cgi 数据!
缓存 cgi 数据的流程和缓存静态资源的流程主要有2个差别,上图标红的地方:
页面展示2次需要考虑页面跳动的体验问题,选择权在于业务本身!
这是我们辅导上课页接入该功能后的首屏优化效果:
动态数据缓存是否有意义还需要额外的逻辑来判断,这块暂时是没有做的,后续会补上相关统计
还能缓存什么?我们想到了直出的 html
这里就不展开讲了,因为我们的 jax 同学已经分享了一篇优秀的文章《企鹅辅导课程详情页毫秒开的秘密 - PWA 直出》,可以去看看哈~
PWA 与离线包本质上是一样的,都是离线缓存
正好,我们 PC 客户端的离线包系统年久失修,在这个契机下,我们启动了使用 PWA 替换离线包的方案!
核心流程不变,基本和缓存静态资源的流程是一致的
但是离线包系统是非常成熟的系统,要完全替换掉它还需要考虑许多方面的问题。
离线包有个自动更新的机制,每隔一段时间就会去请求离线包管理系统是否有更新,有的话就把最新的离线包拉下来自动更新替换,这样只需要1次跳转就能展示最新的页面。
SW 没有自动更新的逻辑,它需要在页面加载(一次跳转)之后才会去请求 sw.js,判断有变化才会进行更新,更新完了要等到下一次页面跳转(二次跳转)才能展示最新的页面。
这里有两个方案:
我们使用第2个方案,部分代码如下:
在检测到 sw 更新之后,我们可以选择强刷,或者提示用户手动刷新页面,具体实现页面可以通过监听事件来处理
更多详细的实现方案可以参考这篇文章哈:How to Fix the Refresh Button When Using Service Workers: https://redfin.engineering/how-to-fix-the-refresh-button-when-using-service-workers-a8e27af6df68
一般离线包是打进 app 的安装包一起发布的,在用户下载安装之后,离线包就已经存在于本地,因此第一次打开就能享受到离线包的缓存。
但是 sw 没有这个能力,同样我们也有两个方案:
我们使用第2个方案,因为我们的 app 启动会先让用户登录,如下图所示:
注:这里 app 不是移动端 app,是 pc 的客户端 app
有时候我们不想使用离线缓存能力,比如在我们开发的时候
在离线包系统,通常会有一个开发者选项是【屏蔽离线包】
SW 也是需要这种能力的,这个方案就比较简单了,在 sw.js 的逻辑里有一个全局的开关,当开关关闭时,就不会走缓存逻辑
因此,我们可以在 dev 环境下把开关关闭即可达到屏蔽的作用
当我们发布了一个错误代码的时候,我们需要快速降级容错的能力
在离线包系统里面有个过期的功能,可以把某个版本设置过期,也就是废弃掉:
我们利用之前提到的全局开关,通过一个管理接口来设置开关的起开和关闭,即可达到快速降级的目的:
整个流程大致是这样:
请求管理接口是轮询的,这里后续有计划会改成 push,这样会更加及时,当然还要详细评估方案之后才能落实。
我们把上述功能集成到了一个 webpack 插件当中,在构建的时候就自动输出 sw.js 并把相关内容注入到 html 文件中,该插件正准备开源哈~
未来对于 PWA 还能做些什么?笔者以为有以下 2 个方面
目前通用的能力已经基本挖掘完成,但是 SW 因为它独特的特性,它能做的事情太多了,但是具体要不要这么做也是因业务而异,而且这些内容可能会很复杂,所以我称为业务深耕。
SW 什么特性?请看下面 2 张图就可以理解了
这种架构相信已经能够看出来了,没错,SW 有间件(层)的特性,那它能做的东西就太多了(虽然 SW 是用户端本地中间层)
简单举几个例子:
回到最开始,PWA 是一项令人兴奋的技术,但是浏览器兼容有限,因此期待并关注 PWA 技术的发展是很有必要的!
当然,能推动就更好了!比如推动我们的 X5 内核尽快支持新特性。
IMWeb 团队隶属腾讯公司,是国内最专业的前端团队之一。
我们专注前端领域多年,负责过 QQ 资料、QQ 注册、QQ 群等亿级业务。目前聚焦于在线教育领域,精心打磨 腾讯课堂 及 企鹅辅导 两大产品。
社区官网:
http://imweb.io/
加入我们:
https://hr.tencent.com/position_detail.php?id=45616
扫码关注 IMWeb前端社区 公众号,获取最新前端好文
微博、掘金、Github、知乎可搜索 IMWeb 或 IMWeb团队 关注我们。
👇点击阅读原文获取更多参考资料