前言
关于电商APP
来讲,运用H5
技能开发的页面占比很高。由于H5
加载速度十分依赖网络环境,所以为了进步用户体会,针对H5
加载速度的优化十分重要。离线包
是最常用的优化技能,经过提早下载H5
烘托需求的HTML/JS/CSS
资源,加载时直接运用本地缓存资源防止额定的网络恳求进步加载速度。本文主要是介绍团队在离线包技能计划上的探究,以及根据prefetch
的离线包完成计划怎么削减保护本钱和开发本钱。
现有计划
离线包技能发展到现在已经比较老练。离线包技能主要是分为两部分,一部分是客户端离线包容器,另一部分是线上离线包渠道。
离线包容器
•资源恳求阻拦
– 阻拦H5
资源恳求,当存在本地缓存资源时直接回来运用
•资源缓存
– 资源下载、资源缓存战略、增量更新战略
离线包渠道
•资源办理
– 装备H5
页面对应的离线资源、公共离线资源、CDN
寄存离线资源包
•发布体系
– 实时发布、灰度才能、版本控制
下面先介绍一下常见的技能完成办法:
资源恳求阻拦办法
Android
Android
完成相比照较一致,主要是经过WebView
自带的shouldInterceptRequest
API 阻拦资源恳求,回来对应的离线资源即可完成离线包
功能。
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 计划
WKURLSchemeHandler
是iOS11
引进的新特性,能够经过此 API 来阻拦H5
的网络恳求。
计划存在的问题
不支撑HTTP/HTTPS协议
•不支撑HTTP/HTTPS协议
– 由于WKURLSchemeHandler
API 自身的规划,只能阻拦自定义协议并不支撑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
提早加载HTML
,WebView
会下载资源到设备中。一起能够直接复用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
引用的资源主动断定为公共资源
提示:一般资源办理,特别是公共资源长时刻保护之后更难办理,许多时分增加之后不知道是否有被运用不会删除。
资源聚合流程
经过运行主动化脚本的办法,根据Puppeteer
和Performance Timing
API,主动计算出需求下载的离线包资源及时更新。
怎么断定首屏资源
运用浏览器自带的PerformanceTiming
API断定。domInteractive
是浏览器完成对一切HTML
的解析并且DOM构建完成的时刻点。在domInteractive
之前加载的资源既为阻塞
首屏烘托的资源。一起需求过滤掉一些不需求缓存的资源,现在咱们只收集JS/CSS
会阻塞烘托的资源。
客户端
客户端完成相对简略,APP 发动后
初始化一个新的WebView
容器后台静默加载,Android
端加载prefetch.html
,iOS
端加载preload.html
。加载完成后释放WebView
容器,之后不会形成其他功能损耗。尽管每次发动都会从头触发下载逻辑,可是只会进行差异化下载
本地缓存中不存在的资源文件。
其他优化
提早加载 WebView
由于 APP 发动后初次初始化WebView
会包含Web
引擎的初始化,初始化耗时会更高。所以咱们预下载资源时也提早初始化了WebView
,之后打开H5
时能够削减100-200ms
初始化耗时。
提早打通登录态
由于大部分事务H5
都需求登录态,所以APP
在初次打开H5
时,需求将原生
登录态信息同步到 H5cookie
中,会有1次额定的302跳转
耗时。咱们在预加载资源时提早打通登录态,之后打开H5
时能够削减100-200ms
302跳转耗时。
接口预拉取
一起也供给了接口预拉取的才能,能够H5
加载前提早拉取首屏接口数据,进步加载速度。
完成过程中遇到的问题
iOS体系
不支撑prefetch
iOS
体系web内核并不支撑prefetch
特性,所以针对iOS咱们采用preload
来替代。Android
渠道下发link-prefetch
,iOS
渠道下发link-preload
进行差异化处理。
提示:
prefetch
相比preload
功能更好。prefetch
下载的优先级没有preload
高,防止影响其他网络恳求速度。preload
会将JS
/CSS
进行解析增加到内存,形成必定的额定耗费。
preload 不支撑 HTML
iOS
体系preload
特性并不支撑HTML Document
的提早加载。不过这一点关于咱们影响不大,由于现在咱们事务H5
的HTML
一般会做必定的服务端烘托逻辑,并不支撑缓存战略。(例如聚合一部分的公共 JS)
多域名资源不同享
iOS
体系中WebView
针对不同域名H5
运用的其他资源并不能同享。例如https://www.jd.com/index.html
和https://www.jingxi.com/index.html
尽管是同一个网页,内部都有运用相同的JS/CSS/图片
资源,可是根据iOS
体系中WebView
缓存战略完成,每一个域名的资源运用独立
的空间办理,并不能同享运用需求重复下载。由于咱们自身H5
支撑jd.com
和jingxi.com
双域名拜访,所以咱们在APP端
增加了域名替换的逻辑,尽可能将咱们自身的事务收敛到jingxi.com
域名,进步缓存资源使用率。
提示:即便不运用离线包,这也是一个不错的优化战略。
Android 体系
磁盘空间不足触发Crash
部分设备在运用prefetch
下载资源时,由于设备自身磁盘空间不足导致Crash
。所以咱们在资源下载
前加了一个额定的磁盘空间查看战略,当磁盘空间太低时不进行下载。
总结
prefetch 计划
咱们经过使用体系浏览器
自身供给的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
作者:京东零售 何骁
来历:京东云开发者社区