有赞 webview 加速平台探索与建设(一)
1. 缘起
说起 webview 与 h5,对整个移动开发业界的人来讲,都是又爱又恨。爱其功能强大、可动态发布、又多端复用。。。又恨其加载慢、响应慢、体验不佳。慢、慢、慢的问题,往往让开发挠头、让客户骂娘!天使与恶魔的共同体,好的坏的都那么明显。
业务快速迭代,h5 页面往往承担着一家公司的大部分流量来源,这对有赞也不例外。优化 h5 的加载,提升客户体验,收益和价值都是巨大的。
2. 怎样做 webview/h5 加速?
要提升 h5 的加载体验,首先要弄清楚的是,到底是什么影响了 h5 的打开速度。这是一个系统性的问题,涉及到移动端、前端、后端多个领域、整条链接的加载优化。本文将只聚焦于从移动端的角度怎样做优化。
2.1 从WebView.loadUrl(url)
讲起
当我们开始加载一个网页,从调用WebView.loadUrl(url)
开始,系统到底做了哪些事情,各个阶段的消耗情况如何?
从移动端的角度来看,一个网页的加载过程总体分为上图所示的几个步骤,每个步骤消耗的时间累积影响整体的加载速度。
我们对于有赞的的一些典型 h5 页面做了各阶段的测试(在 wifi 条件下),总结如下表:
阶段 | 耗时 | 说明 |
---|---|---|
webview 初始化 | 约 100ms~250ms | 首次需加载 webview 内核耗时 |
dns 解析 +tcp 连接 | 20ms~1.5s | 波动较大,最差的情况遇到过 1.5s 的 case |
html 下载 | 约 200ms~600ms | 多数情况 400ms 左右(wifi) |
html 解析 | 100ms~150ms | |
静态资源下载 | 50~200ms | 此为同步资源消耗,异步资源未计 |
2.2 到底什么更影响加载体验?——白屏时间 or 整体加载时间
从直观的角度讲,当打开一个 h5 页面的时候,页面会有较长时间的白屏——此所谓响应慢。反应到上图的系统过程中,它包括:webview 内核初始化(首次打开)、DNS 解析及建连、请求 html 并下载、解析 html 及同步资源这几步。我们把这个过程记为白屏时间。白屏时间在 h5 页面加载的前半程,对整体的体验影响最大。
而页面的整体加载时间,还包括异步资源、数据请求的完成,往往是在当前页面已经可看、可操作的后台继续进行着。对用户的体验影响较小(除非首屏有大块区域需要这种异步资源或者数据请求作展示,比如:有赞的商品详情页顶部大部分是商品轮播图)。
从上述表格来看,页面整体的加载过程在 1.2s 左右,白屏时间至少 400ms~800ms。这是在 wifi 条件下测得的数据,换成移动网络 2G/3G,情况会更糟!
2.3 从哪些方面着手?
清楚了各个阶段的消耗,以及对体验影响最大的白屏时间。从以下方面入手:
- webview 内核的加载
这里指 webkit 内核的初次加载,包含 java 类的 load、动态库查找 load 到内存中,也包括 webview 的创建。可考虑的一个做法是,应用启动时全局加载 webview 内核,以空间换时间(此法大约有 10M 左右的内存占用)。
- DNS 解析优化
DNS 解析情况好的时候,几毫秒、十几毫秒就完成了。差的时候,可能需要花很多时间(遇到过需要 1.5s 的 case)。域名收敛、对 DNS 做 prefetch, 尤其对优化一些长尾 case 非常有用。
-
静态资源缓存
如果对 css/js、图片、或者其他如 ttf 等静态资源,预先缓存到本地,可以省去从远端拉取静态资源的消耗。在我们的解决方案中,对于初次、二次打开页面,静态资源的命中率都可以做到 80%~100%。
但是必须清楚,除了那几个解析渲染首屏 html 必要的、同步的静态资源 (css/js), 提升静态资源的命中率整体对于白屏时间的优化是比较有限的。静态资源的加载大多是在页面加载的后半程。
-
html 预取及缓存
从上面数据可以看出,下载 html 内容的消耗在 400ms 左右,这是白屏时间的一大来源。如果能缩减这部分时间,则可以大大减少白屏。将 html 内容提前下载到本地,
WebView.loadUrl(ur)
时直接从本地加载,速度要快得多。但 html 本身是常变化的,如果本地缓存的 html 内容过期了怎么办?
如果 html 的内容是用户相关、需要登录才能看的怎么办?
不过,html 的预取、缓存虽然有诸多限制,但并非没有适用的场景!
在有赞的 webview 加速解决方案中,通过对可缓存的 html 范围做限制,解决了店铺首页、活动页的 h5 打开提速问题。这些页面都是属于变化较少、并不私有的页面。
更重要的是:这些页面,往往都是 webview 的入口页(从 native 到 webview),是最可能产生白屏的地方。进入这些页面后再点击跳转到其他页面属于 webview 内跳转,其体验尚可。
3. 有赞前端体系及 h5 资源分析
3.1 静态资源区分
有赞 h5 页面中的资源整体要分成两种:
一种是有赞统一资源,这指的是页面共有的 css/js 等资源,属于有赞的页面都可能会使用;
另一种商家特有的差异资源,只有在这个商家的店铺当中才会用到,这部分主要是商家上传的商品图片。
举几个实例:
类型 | 路径 | 说明 |
---|---|---|
有赞统一资源 | /v2/wscwap/build/css/showcase/goods_c84308e66177da54cc8371e5d9f65767.css 、 /v2/build/wap/ump/send_coupon_f4f485ecf5.js | |
商家差异资源 | /upload_files/2017/12/14/FlF05IkscTy9TACqGg129U8Kqxex.jpg?imageView2/2/w/980/h/980/q/75/format/webp |
假如有赞的两个商家 A 和 B,分别有自己的店铺或客户端。商家 A 和 B 都会共同用到有赞的一些基础 css/js 静态资源。但 A、B 各自的商品图片等静态资源是相互隔离的。
除了共用的基础 css/js 等静态资源,在 A 的端中只能缓存自己的图片资源,B 的端也同样只需缓存 B 自己的图片资源。
这里有必要解释一下“商家的端”的概念及具体形式:拿有赞典型的两个产品来说,一个是微商城,一个是 App 开店。在微商城客户端中,商家 A 和 B 分别用自己的帐号登录、管理自己的店铺,这里,商家的端 = 微商城客户端 +A/B 的店铺。
而在 App 开店中,有赞提供一个基础的 AppSDK,包装有赞的商品系统、营销系统等后台服务,商家 A 和 B 在自有的客户端 App 中集成这个基础 SDK,就可以使用有赞的服务。这里,商家的端 = 商家 A/B 自有的 app+AppSDK
不同的商家的端,所需要的资源是不相同且必需隔离的。这一特点会影响到我们后面的系统设计。
3.2 静态资源变化与路径
做静态资源缓存的一大要点是如何解决资源变化后的实时更新问题?以及系统如何自动发现资源已经变化?变化后如何更新缓存?
我们的前端每天都在发布,每天都有一定数量的 css/js 等需要更新。
我们的商家们每天都在做生意、上传新的商品,每天都在添加新的图片。
对于 css/js 等一类资源,我们采用webpack
打包,资源内容的变化就一定会引起资源路径变化。比如:/v2/build/wap/ump/send_coupon_f4f485ecf5.js
这个资源,它的后缀部分f4f485ecf5
其实是这个资源文件的 md5 值前 10 位。
对于图片类的资源,每次上传图片,它也会有一个唯一的路径。比如:/upload_files/2017/12/14/FlF05IkscTy9TACqGg129U8Kqxex.jpg
。
变化后的资源 => 不同的路径, 这个特点对于解决如何发现变化、缓存实时更新的问题真是有太多的方便!
3.3 html 页面特点及区分
有赞的 html 页面有很多种,各有特点:有的变化很快,有的属于隐私页面。但也有一些相对稳定的入口页、活动页。
html 的加速,除了从 html 获取的全链接下手(包括服务器、业务方、协议层等),单就做 html 缓存预取来说,其实是相当难做的。因为实时性的问题,难以解决。尤其有赞的 html 页面并未做前后端分离。它的所有页面内容,包括一部分页面数据都是在服务器端中拼接直出的。
从之前的数据分析,html 内容的获取是占白屏时间的大头。所以对它做优化是项目是否取得显著成效的关键。但是如果把前后端的同学聚集起来做大幅度的改造:前后端分离、优化协议。。。恐怕长期也难见成效。业务的发展和成长是第一位的。
如果我们把要优化 html 页面的范围缩小,聚焦于那些相对稳定的微页面 / 店铺首页、商品详情页、活动页,我们可以牺牲一点点的实时性,来换取加载体验极大提升。而恰恰这些页面往往是 webview 的入口页,也是访问最多的页面。对它们的加载做优化,可以得到最佳的投入收益比。
4. 金翅 (goldwing)——有赞移动端 h5 加速平台
初看这个名字可能会觉得很怪,它很中国化,英文代号也很拉风。金翅是一种常见的鸟,我们寄寓这套系统能给我们的 app 带上翅膀。
金翅是我们对有赞移动端 h5 加速解决方案的总称,它包括 Android/iOS 客户端 sdk、java 后台服务、还有 nodejs 写的管理控制台。
在这套系统中,我们解决了以下几个问题:
* 有赞所有静态资源的缓存,包括统一的 css/js 等资源,及商家端特有的图片等资源;
* 店铺首页 / 微页面、商品详情页、活动页等入口页的 html 加速;
* 动态化配置、在线接入及管理。
在不约束下载条件(如:wifi)的情况下,不论是首次、二次以后打开页面,静态资源的命中率达到了 80%~100%。
对于 html 的加速优化前后,请看如下动图对比:
* 不使用优化
- 使用优化后(静态资源缓存 +html 缓存预取)
效果还是还当的明显的!未使用优化的第一张图,可明显看出有较长时间的白屏效果。而使用优化后的第二张图,效果已经可以近于 native 化的加载体验了。
关于金翅如何做静态资源的缓存?如何做 html 的加速、缓存预取?后文将单独做专题讲述。
5. 结语
做这套 h5 加速解决方案,前后时间大概有三个月之久。这期间小组内同事们除了要继续做手头的业务,其他大部分的精力都投入了这项工作当中。
这期间我们参考了业内许多其他公司同仁的分析、思考与总结,结合有赞业务的特点完成了这套 h5 加速解决方案。
目前这套体系稳定的接受着千万级流量的洗礼,我们同时也在公司内的更多业务线中推广铺开。