我们统计的网络耗时是从WebView load URL开始到页面首行这段时间,实际上包括一部分页面加载,WebView内核的启动,网络组件和渲染组件的加载,所以耗时比较高。 这里肯定也有优化空间,但当我们的客户端团队正要优化网络耗时这部分的时候,我们的业务形态变了。之前是产品经理配置什么页面就显示什么,所有用户看到的内容都是一样的,现在产品经理说每个用户进入到商城首页看到的内容要完全不一样。 以下图为例,像左边首页的内容是随机推荐的,右边实际上是通过机器学习根据用户过去表情发送的行为习惯和我们后台的物品做计算匹配,根据用户的喜好行为而推荐的内容。 每个用户进来看到的内容都是不一样,那么静态直出这种模式行不通了,因为我们不可能把所有用户的页面都在后台生成然后发到CDN上,然而这种模式也有很简单的办法来解决。 动态直出 我们并不在CDN上存储HTML,而是后台Node.js服务器上动态拼接出整个HTML文件,数据来源是从dataServer去拉取。 这种模式解决了产品的需求,但引入了新的问题。WebView获取html要请求Node.js,Node.js要进行后台页面拼装,中间的网络耗时和后台运算耗时比我们想象中要大。在这个过程中,整个页面是无法渲染的,用户进入我们商城首页则看到一片空白,产品经理同样无法接受,用户也不买单。 另外这种模式下几乎无法利用WebView本身的缓存,因为后台直出同样在CSS/JS已经全部都在后端执行,WebView很难将一个纯粹的静态HTML全部缓存下来。为了解决上述问题,我们引入了动态缓存的机制。 动态缓存 同样我们不让WebView直接访问我们的Node.js服务器,我们在这中间加上之前提到地类似offlineCache的中间层sonicBridge,这个中间层首先会从Node.js服务器下载完整的HTML给WebView,同时会把下载回来的内容在本地完整地做缓存。 我们之前是全网所有用户缓存同一份HTML,现在修正为全网用户缓存的内容都是从真实server里拉回来的页面。 当用户第二次进入页面时,sonicBridge会优先把本地缓存的页面提交给WebView,用户进入页面不需要等待网络请求就可以看到内容,这对用户侧在速度上的体验提升比较大,但它又引入了另外一个问题。 实际上用户每次打开WebView看到的内容都不一样,Node.js每次返回的数据都是最新的,因此拉回来的数据我们必须让WebView进行reload,这给用户的体验是:明明已经打开了本地缓存好的HTML并且看到内容,但一操作页面却整个reload了。在一些低端机型上WebView reload非常耗时,用户能很明显感觉到整个WebView H5页面白屏一下,然后才刷新出新的内容。 结合前面提到的静态直出局部refresh部分DOM的经验,我们可以减少网络传输量和减少提交页面的数据量。我们首先做的事情是减少网络传输量,避免refresh的时间太靠后。 减少传输数据 我们改变了Node.js组HTML的协议,当sonicBridge在第二次请求数据的时候,Node.js服务器并不会返回整个HTML给sonicBridge,而是返回给我们称为data数据的部分。 拿到data数据之后,我们和H5页面做了约定,由native侧调用页面的固定刷新函数,并传递数据给页面。页面会去局部刷新自己的DOM节点,这样即使页面需要刷新也不会reload整个页面。 具体从数据内容的流程上看,首次sonicBridge加载页面返回的仍是完整的HTML,同时会返回我们称为template-tag的id,这个template-tag会标记这个页面中静态不变的那部分hash值,这措施是为了控制缓存。在返回的HTML中我们会也有一些标记,比如sonicdiff-banner,这个banner决定了它的刷新id是什么。 (责任编辑:本港台直播) |