前言

关于电商APP来讲,运用H5技能开发的页面占比很高。由于H5加载速度十分依赖网络环境,所以为了进步用户体会,针对H5加载速度的优化十分重要。离线包是最常用的优化技能,经过提早下载H5烘托需求的HTML/JS/CSS资源,加载时直接运用本地缓存资源防止额定的网络恳求进步加载速度。本文主要是介绍团队在离线包技能计划上的探究,以及根据prefetch的离线包完成计划怎么削减保护本钱和开发本钱。

现有计划

离线包技能发展到现在已经比较老练。离线包技能主要是分为两部分,一部分是客户端离线包容器,另一部分是线上离线包渠道。

离线包容器

资源恳求阻拦 – 阻拦H5资源恳求,当存在本地缓存资源时直接回来运用

资源缓存 – 资源下载、资源缓存战略、增量更新战略

离线包渠道

资源办理 – 装备H5页面对应的离线资源、公共离线资源、CDN寄存离线资源包

发布体系 – 实时发布、灰度才能、版本控制

下面先介绍一下常见的技能完成办法:

资源恳求阻拦办法

Android

Android完成相比照较一致,主要是经过WebView自带的shouldInterceptRequestAPI 阻拦资源恳求,回来对应的离线资源即可完成离线包功能。

iOS

iOS由于苹果的约束,完成办法相对复杂许多。

NSURLProtocol 计划

运用NSURLProtocol阻拦一切WebView内发出的恳求。

计划存在的问题

Body丢掉

由于WKWebView自身是运用多进程模式,WebView资源网络恳求并不在APP进程中。iOS体系现在的完成,当阻拦HTTP网络恳求时会丢掉Body,所以需求处理Body丢掉的问题。一种办法是替换WebView内部的网络 API,例如Fetch/XMLHttpRequest,可是并不能覆盖一切场景。另一种办法是网络恳求走原生API桥接的办法,可是这需求H5进行适配有必定的侵入性

运用私有API

WKWebView自身并不支撑网络恳求阻拦,当咱们需求阻拦网络恳求时,需求运用体系私有API经过ObjC Runtime的办法动态调用。存在必定的审阅危险,例如Apple审阅时不允许运用被拒。另外由于并不是体系暴露出的 API,内部完成未来可能会改动。

WKURLSchemeHandler 计划

WKURLSchemeHandleriOS11引进的新特性,能够经过此 API 来阻拦H5的网络恳求。

计划存在的问题

不支撑HTTP/HTTPS协议

不支撑HTTP/HTTPS协议 – 由于WKURLSchemeHandlerAPI 自身的规划,只能阻拦自定义协议并不支撑HTTP/HTTPS协议。一种办法是原生加载H5时运用自定义协议或H5内资源运用自定义协议。另一种办法是hook体系办法支撑HTTP/HTTPS协议,可是这会带来必定的危险和不确定性。

Cookie 问题

WKURLSchemeHandler不会处理响应里的Set-Cookie,所以需求自行处理。

Body丢掉问题

此计划相同存在Body丢掉问题。

Local Server 计划

Local Server办法是经过在APP运行时发动一个本地服务器,恳求H5时拜访本地服务器,本地服务器查看是否能够运用本地离线资源。

计划存在的问题

虚拟链接

虚拟链接 – 由于需求运用虚拟链接拜访本地服务器,所以会带来cookie同步等问题需求解决

资源耗费

•本地服务器有额定的内存CPU耗费

PWA 计划

PWA供给了一整套Service Worker API来完成离线H5才能,包含资源的下载、更新、缓存战略等。只不过iOS体系自身没有供给默许的完成,需求自完成一整套相关的 Service Worker API,复杂度和工作量比较高。

离线包办理渠道

增量更新战略

由于一个H5页面的离线包资源一般是聚合到一个ZIP压缩包中进行下载,为了防止只更新了部分资源导致全量下载,所以需求供给差异化更新才能,只需求下载变更的资源。

prefetch计划介绍

规划目标

分析了现在业界常用的离线包计划后,咱们针对离线包的规划目标做了一轮整理。一部分是前端团队的诉求,一部分也是咱们期望完成的目标:

低侵入性

H5低侵入 – 接入离线包无需做额定适配,尽可能关于前端做到无感知。一方面能够削减前端适配本钱和代码复杂度,另一方面也有利于咱们更好去推进覆盖更多的 H5 网页

原生无侵入 – 不需求运用特定的WebView容器

低保护本钱

由于离线包涉及到资源的提早下载,所以需求提早装备好需求运用的资源URL用于下载。现有计划一般需求一个渠道去办理这些资源,针对每一个需求运用离线包才能的H5页面,装备相关的静态资源文件URL列表。可是会带来一个问题便是每次更新都需求人工去保护整个静态资源URL列表,咱们期望尽可能防止人工去保护

个人观点:这儿更好的办法是离线包体系和前端发布体系打通,发布时主动更新静态资源列表到离线包资源办理体系。

低运行时耗费

低网络耗费 – 只下载必要的资源,防止无用资源下载,重复资源下载。

低CPU/内存 – 尽可能少的内存和CPU耗费,当不运用时做到零负荷

完成复杂度低

后台办理体系 – 由于人力的问题暂时没办法支撑开发一个完整的离线包后台办理体系

客户端容器 – 客户端的完成尽可能简略,能够更快速的上线一起防止带来额定的问题

详细完成

完成思路是使用H5浏览器自带的prefetch才能。经过将离线包资源聚合到单个HTML中,APP发动后运用WebView提早加载HTMLWebView会下载资源到设备中。一起能够直接复用WebView自带的离线缓存才能和差异化资源更新才能。

prefetch.html

<html>
  <head>
    <!--公共资源-->
    <link rel="prefetch" href="https://wq.360buyimg.com/js/common/dfd0ab35.js">
    <link rel="prefetch" href="https://wq.360buyimg.com/data/fontRegular.ttf">
    <!--A页面资源-->
    <link rel="prefetch" href="https://wq.360buyimg.com/jxpp/app.css">
    <link rel="prefetch" href="https://wq.360buyimg.com/data/min.js">
  </head>
  <body></body>
</html>
仿制代码

H5 离线包资源聚合

前面有说到不期望让H5事务开发同学手动办理保护离线包资源,所以咱们期望供给一种主动聚合资源的才能。削减后续保护本钱的一起尽可能削减资源的下载。

断定是否敞开离线包

和线上H5功能监控体系打通,根据拜访次数TOP排名来主动断定是否敞开离线包预加载

部分H5假如需求预热能够额定增加

聚合资源

•根据实际加载情况计算出需求预下载的资源比人工保护愈加精确

•被多个H5引用的资源主动断定为公共资源

提示:一般资源办理,特别是公共资源长时刻保护之后更难办理,许多时分增加之后不知道是否有被运用不会删除。

资源聚合流程

经过运行主动化脚本的办法,根据PuppeteerPerformance TimingAPI,主动计算出需求下载的离线包资源及时更新。

基于 prefetch 的 H5 离线包方案 | 京东云技术团队

怎么断定首屏资源

基于 prefetch 的 H5 离线包方案 | 京东云技术团队

运用浏览器自带的PerformanceTiming API断定。domInteractive是浏览器完成对一切HTML的解析并且DOM构建完成的时刻点。在domInteractive之前加载的资源既为阻塞首屏烘托的资源。一起需求过滤掉一些不需求缓存的资源,现在咱们只收集JS/CSS会阻塞烘托的资源。

客户端

客户端完成相对简略,APP 发动后初始化一个新的WebView容器后台静默加载,Android端加载prefetch.htmliOS端加载preload.html。加载完成后释放WebView容器,之后不会形成其他功能损耗。尽管每次发动都会从头触发下载逻辑,可是只会进行差异化下载本地缓存中不存在的资源文件。

其他优化

提早加载 WebView

由于 APP 发动后初次初始化WebView会包含Web引擎的初始化,初始化耗时会更高。所以咱们预下载资源时也提早初始化了WebView,之后打开H5时能够削减100-200ms初始化耗时。

提早打通登录态

由于大部分事务H5都需求登录态,所以APP在初次打开H5时,需求将原生登录态信息同步到 H5cookie中,会有1次额定的302跳转耗时。咱们在预加载资源时提早打通登录态,之后打开H5时能够削减100-200ms302跳转耗时。

接口预拉取

一起也供给了接口预拉取的才能,能够H5加载前提早拉取首屏接口数据,进步加载速度。

完成过程中遇到的问题

iOS体系

不支撑prefetch

iOS体系web内核并不支撑prefetch特性,所以针对iOS咱们采用preload来替代。Android渠道下发link-prefetchiOS渠道下发link-preload进行差异化处理。

提示:prefetch相比preload功能更好。prefetch下载的优先级没有preload高,防止影响其他网络恳求速度。preload会将JS/CSS进行解析增加到内存,形成必定的额定耗费。

preload 不支撑 HTML

iOS体系preload特性并不支撑HTML Document的提早加载。不过这一点关于咱们影响不大,由于现在咱们事务H5HTML一般会做必定的服务端烘托逻辑,并不支撑缓存战略。(例如聚合一部分的公共 JS)

多域名资源不同享

iOS体系中WebView针对不同域名H5运用的其他资源并不能同享。例如https://www.jd.com/index.htmlhttps://www.jingxi.com/index.html尽管是同一个网页,内部都有运用相同的JS/CSS/图片资源,可是根据iOS 体系中WebView缓存战略完成,每一个域名的资源运用独立的空间办理,并不能同享运用需求重复下载。由于咱们自身H5支撑jd.comjingxi.com双域名拜访,所以咱们在APP端增加了域名替换的逻辑,尽可能将咱们自身的事务收敛到jingxi.com域名,进步缓存资源使用率。

提示:即便不运用离线包,这也是一个不错的优化战略。

Android 体系

磁盘空间不足触发Crash

部分设备在运用prefetch下载资源时,由于设备自身磁盘空间不足导致Crash。所以咱们在资源下载前加了一个额定的磁盘空间查看战略,当磁盘空间太低时不进行下载。

总结

prefetch 计划

基于 prefetch 的 H5 离线包方案 | 京东云技术团队

咱们经过使用体系浏览器自身供给的prefetch预加载资源才能和HTTP离线缓存才能,完成了一套相对轻量的离线包解决计划,H5首屏功能提高基本上和其他计划一样(除了iOS体系上不支撑HTML离线资源)。一起经过离线资源主动计算/主动更新的办法,不需求额定的离线包资源办理体系,削减后续的保护本钱。

这套计划尽管在完本钱钱和保护本钱上相比照较低,可是由于完成办法的挑选也存在一些不足需求后续完善。例如无法阻拦网络恳求扩展更多才能,一起依赖浏览器自身的缓存战略也存在一些不可控,例如Android端浏览器内核过多,资源需求彻底恪守HTTP缓存战略。一起离线资源主动计算/主动更新才能并不简单笼统出一套标准化的计划适用于不同公司的事务。可是技能完成计划一般都是在做各种权衡和取舍,这是咱们以为现在相对低本钱的一套完成计划。

离线包的价值

个人以为提早下载资源的离线包办法带来的首屏加载收益并没有那么高。原因如下:1.提早下载过多离线资源也会带来更多的网络耗费。2.大部分页面自身不具备离线运用的才能(需求网络拜访接口)。3.离线包也只是优化第一次加载的速度,由于资源自身就能够设置HTTP的缓存战略防止重复下载。H5页面首屏加载应该更多关注页面自身的烘托功能,例如JS/CSS解析耗时,直出还对错直出,首屏接口速度等。

更有价值的在咱们怎么经过阻拦网络恳求增强更多的才能,例如供给HTTPDNS原生/H5复用图片缓存等才能。

扩展链接

•WKWebView 恳求阻拦探究与实践

•评估要害烘托途径

•离线Hybrid容器怎么做到接近100%秒开?

•prefetch特性支撑

•preload特性支撑

•WKWebView离线化计划——完成Service Worker API

作者:京东零售 何骁

来历:京东云开发者社区