上一篇我们讲解了如何在前端做项目优化,这篇来接着讲在客户端应该如何优化?
客户端优化
接着轮到客户端出场了,桌面时代受限于浏览器,H5 页面无法做更多的优化,现在 H5 页面是内嵌在客户端 APP 上,客户端有更多的权限,于是客户端上可以超出浏览器的范围,做更多的优化。
HTML 缓存
先接着缓存说,在客户端有更自由的缓存策略,客户端可以拦截 H5 页面的所有请求,由自己管理缓存,针对上述 HTML 文件的“缓存”和“更新”之间的矛盾,我们可以用这样的策略解决:
1.在客户端拦截请求,首次请求 HTML 文件后缓存数据,第二次不发请求,直接使用缓存数据。
2.什么时候去请求更新?这个更新请求可以客户端自由控制策略,可以在使用本地缓存打开本地页面后再在后台发起请求询问更新缓存,下次打开时生效;也可以在 APP 启动时或某个时机在后台去发起请求预更新,提升用户访问最新代码的几率。
这样看起来已经比较完美了,HTML 文件在用客户端的策略缓存,其余资源和数据沿用上述前端的缓存方式,这样一个 H5 页面第二次访问从 HTML 到 JS/CSS/Image 资源,再到数据,都可以直接从本地读取,无需等待网络请求,同时又能保持尽可能的实时更新,解决了缓存问题,大大提升 H5 页面首屏启动速度。
问题
上述方案似乎已完整解决缓存问题,但实际上还有很多问题:
1.没有预加载:第一次打开的体验很差,所有数据都要从网络请求。
2.缓存不可控:缓存的存取由系统 webview 控制,无法控制它的缓存逻辑,带来的问题包括:
清理逻辑不可控,缓存空间有限,可能缓存几张大图片后,重要的 HTML/JS/CSS 缓存就被清除了。
磁盘 IO 无法控制,无法从磁盘预加载数据到内存。
更新体验差:后台 HTML/JS/CSS 更新时全量下载,数据量大,弱网下载耗时长。
无法防劫持:若 HTML 页面被运营商或其他第三方劫持,将长时间缓存劫持的页面。
这些问题在客户端上都是可以被解决的,只不过有点麻烦,简单描述下:
1.可以配置一个预加载列表,在APP启动或某些时机时提前去请求,这个预加载列表需要包含所需 H5 模块的页面和资源,还需要考虑到一个H5模块有多个页面的情况,这个列表可能会很大,也需要工具生成和管理这个预加载列表。
2.客户端可以接管所有请求的缓存,不走 webview 默认缓存逻辑,自行实现缓存机制,可以分缓存优先级以及缓存预加载。
3.可以针对每个 HTML 和资源文件做增量更新,只是实现和管理起来比较麻烦。
4.在客户端使用 httpdns + https 防劫持。
上面的解决方案实现起来十分繁琐,原因就是各个 HTML 和资源文件很多很分散,管理困难,有个较好的方案可以解决这些问题,就是离线包。
离线包
既然很多问题都是文件分散管理困难引起,而我们这里的使用场景是使用 H5 开发功能模块,那很容易想到把一个个功能模块的所有相关页面和资源打包下发,这个压缩包可以称为功能模块的离线包。使用离线包的方案,可以相对较简单地解决上述几个问题:
1.可以预先下载整个离线包,只需要按业务模块配置,不需要按文件配置,离线包包含业务模块相关的所有页面,可以一次性预加载。
2.离线包核心文件和页面动态的图片资源文件缓存分离,可以更方便地管理缓存,离线包也可以整体提前加载进内存,减少磁盘 IO 耗时。
3.离线包可以很方便地根据版本做增量更新。
4.离线包以压缩包的方式下发,同时会经过加密和校验,运营商和第三方无法对其劫持篡改。
到这里,对于使用H5开发功能模块,离线包是一个挺不错的方案了,简单复述一下离线包的方案:
1.后端使用构建工具把同一个业务模块相关的页面和资源打包成一个文件,同时对文件加密/签名。
2.客户端根据配置表,在自定义时机去把离线包拉下来,做解压/解密/校验等工作。
3.根据配置表,打开某个业务时转接到打开离线包的入口页面。
4.拦截网络请求,对于离线包已经有的文件,直接读取。
5.离线包数据返回,否则走 HTTP 协议缓存逻辑。
离线包更新时,根据版本号后台下发两个版本间的 diff 数据,客户端合并,增量更新。
光做完这两个对于优化还是完全不足够的,不仅仅是在前端和客户端是需要做优化,还有细节方面也是需要做优化的。这一节就讲到这,稍后再给大家讲讲"阿里技术分享:H5首屏秒开优化方案三、细节优化"。