正文
原文出处
A Tinder Progressive Web App Performance Case Study
Tinder最近对移动端“右滑”了。他们最近出品的响应式的
渐进式网页应用
——
Tinder Online
——已经可以在桌面和移动端使用了,应用采用了新技术做
JavaScript性能优化
,并用
Service Workers
和
Push Notification
分别做了网络弹性和对话约会。今天我们来简单过一遍他们的性能学习之路。
踏上渐进式网页应用的旅程
Tinder Online的目标是在新市场站稳脚跟,力争达到在其它平台上Tinder V1版本的使用体验。
PWA的MVP花了三个月,采用了
React
构架UI库和
Redux
做状态管理。
这些努力的结果就是,渐进式网页应用只使用了10%的流量消耗就达到了Tinder核心的应用体验,这对流量费用昂贵或连接速度慢的地区的人来讲尤为重要:
上图是Tinder Online和原生应用的流量消耗对比。值得注意的是,这并不是横向的比较。PWA只会按需从新路由上加载代码,这些额外的代码加载分散在应用的整个生命周期里面。后续导航消耗流量依旧比下载整个app的要少。
早期征兆显示,对比原生应用,PWA表现出了流畅的滑动体验,更多的消息操作和更长的会话时间。在PWA上:
-
用户的滑动操作更多
-
用户之间发送的消息更多
-
用户的购买量与原生应用持平
-
用户对个人资料的编辑更为频繁
-
用户的会话时间更长
性能
Tinder Online的移动端用户使用最多的设备包括:
-
Apple iPhone和iPad
-
Samsung Galaxy S8
-
Samsung Galaxy S7
-
Motorola Moto G4
通过使用
Chrome用户体验报告
(CrUX),我们了解到大部分的用户在浏览Tinder Online的时候使用的是4G网络:
注:Rick Viscomi最近在
PerfPlanet
中加入了CrUX,Inian Parameshwaran使用了
rUXt
将数据变得更加可视化。
在使用
WebPageTest
和
Lighthouse
(4G下使用Galaxy S7)测试后,我们看到用户在
五秒钟之内
即可加载完毕并进入可交互状态。
当然,在受CPU约束的
中端移动设备
(比如Moto G4)上,仍然存在很多可优化空间:
Tinder正在努力优化他们的体验,未来我们也希望能看到他们在网页性能优化上所做的工作。
性能优化
Tinder使用了很多技术来提升加载速度和减少进入可交互状态之前的时间。他们使用了基于路由的代码分割,并引入了性能预算和资源的长期缓存。
基于路由的代码分割
Tinder网页端最初包含了庞大的JavaScript代码包,这延长了应用的加载时间。这些包中包含了很多并不需要立即加载的代码,因此这些代码可以通过使用
代码分割
打碎。
只加载用户首屏使用的代码,其它的在需要的时候懒加载,这种办法非常有用。
为了达到这一点,Tinder使用了
React Router
和
React Loadable
。他们的应用把路由和渲染信息集中在了一个配置里面,他们发现可以直接在顶层做代码分割。
简介:
React Loadable的的作者是James Kyle,他的初衷是简化以组件为中心的React应用的
代码分割
。
Loadable
是一个高阶组件(一个创建组件的函数),能够在组件层使得
分割
代码包更加简单。
比如我们有两个组件,“A”和“B”。在做代码分割之前,Tinder静态地将所有东西(A、B等等)都引入到主包里面。这种方式很低效,因为我们并不立刻且同时需要A和B两个组件:
在做了代码分割之后,组件A和组件B会在需要的时候再加载。Tinder在JS中引入了React Loadable,
动态导入
和
webpack的魔法注释
(针对命名动态代码块):
针对“vendor”(库),Tinder使用了
CommonsChunkPlugin
将频繁使用的公共库单独打包,这样可以有效利用长缓存:
接着,Tinder使用
React Loadable的预加载支持
来预加载下一页可能会使用到的资源:
Tinder也使用了
Service Workers
来预缓存所有路由层的代码包,并把用户最有可能访问的路由在未做分割的情况下加进了主包中。当然他们也使用了最常用的优化手段,例如通过UglifyJS最小化JavaScript文件的体积:
new webpack.optimize.UglifyJsPlugin({
parallel: true,
compress: {
warnings: false,
screw_ie8: true
},
sourceMap: SHOULD_SOURCEMAP
}),
影响
在引入了基于路由的代码分割之后,他们的主包的大小从166KB降至了101KB,DCL从5.46秒降至4.69秒:
资源的长期缓存
通过使用webpack的[chunkhash]向文件名中加入独一无二的字段,这保证了静态资源的
长期缓存
。
Tinder在依赖中使用了很多开源的库。vendor的[chunkhash]会随着对这些库作出的改变而改变,这就会使缓存失效。为了解决这个问题,Tinder定义了一个
外部库白名单
,并将他们的manifest文件从主代码块中分离出来,以改善缓存。现在两个代码包的大小大约都是160KB。
预加载后期使用资源
作为一名新手,
<link rel="preload">
是一个声明式的命令,指导浏览器预先加载关键的、后续会用到的资源。在一个单页面应用里面,这些资源可能会是JavaScript包。