微信扫描登录

移动端电商类展示页面性能优化实战

本篇文章整理自朱海源4月21日在『ITA1024前端精英群』里的分享实录:移动端电商类展示页面性能优化实战 。

朱海源:苏宁易购移动端前端负责人

enter image description here

本期特邀主持:
林洋(去哪儿资深前端工程师)
本期特邀内容评审团:
汤桂川(广发证券Web前端资深工程师)
吴子房(网易前端技术专家)

近两年移动端的发展非常迅速,而正是这种速度催生了 HTML5 在移动端的发展,其中电商类型的业务更加明显。在 HTML5 还没有那么普及之前,苏宁易购手机客户端绝大部分的业务场景都是原生开发,而今天打开苏宁易购客户端,首页 70% 的页面都是内嵌的 HTML5 页面,这也给前端开发提供了一个很好的土壤,很多新的技术和优化方案不断地从这土壤里生长出来,今天就一起聊一下我们针对移动端 HTML5 页面我们做了哪些优化。

1. 电商展示类页面的特点

日常维护的频道页和大促期间的大促会场页面都是典型的电商展示类页面,页面里主要元素基本都是焦点图,列表,图片楼层,选项卡等,并且绝大部分流量 都消耗在商品图片上,我们做过一个统计,页面里有大焦点图的时候,第一张大图字节数大于整个页面所有 js 和 css 资源总和的页面占了80%,所以所谓电商类展示页面的性能,必然有一部分精力要放在图片上。

2. 图片

样式背景图片处理:

这个是前端最拿手的,在 PC 时代也积累了丰富的经验,比如最常见的雪碧图,高版本浏览器使用 CSS3 替代背景图片,还有 iconfont 方案,根本目的就是为了减少请求数量,在移动端这些方案同样适用,而且移动端有一个先天的优势,对 base64 支持度很好,可以很方便的使用 webpack 等构建工具把一些小于 5KB 的碎背景图片内置到样式表里,更好的利用浏览器缓存。

商品图片处理:

当用户在浏览电商展示类型的页面时,所载入的资源大部分都是运营维护的商品图片和一些促销广告图,上面提到了一张大图的字节数就有可能比整个页面的 js 和 css 资源的总合还要大,针对这个问题虽然前端能做的事情有限,但不代表没有办法。

我们采用了目前各大电商普遍采用的方案,在支持 webp 格式的浏览器使用 webp 格式的图片,不支持的暂时还使用原图,虽然解决不了所有问题,但可以做到安卓浏览器下图片使用 webp 格式,节省了大部分用户的流量。

刚才说的是手机浏览器下不完美解决方案,而客户端内嵌 H5 页面已经实现 iOS 和安卓都可以支持 webp 格式,用户在客户端 webview 打开 H5 页面,页面所使用的商品图片都可以很好的支持 webp,同时利用了客户端自身的缓存机制,在缓存期间内再次访问同一个页面,基本可以达到秒开。

客户端同时提供了网络环境判断方法,2G,3G 下我们会加载低质量图片,4G 下加载正常图片,WIFI 下加载高质量图片,更好的节省了用户的流量同时也加快了页面显示的速度。

3. 首屏

自从首屏这个概念被提及之后已经变成展示类页面性能的一个主要考核标准,所谓页面的前端性能优化很多时候就变成了首屏性能优化。移动端因为网络环境 的不稳定,所以经常会出现白屏现象,用户在打开页面会先白屏一段时间才出现内容,这个体验非常不好,所以解决首屏性能问题的关键就是减少白屏出现的概率。

先来说一下通用的处理方案:

  • 域名收敛
  • html 文档压缩
  • 静态资源合并
  • 首屏以外业务延迟加载,资源按需加载,图片懒加载
  • 雅虎军规常规优化

上面这些优化点已经普及到了开发规范中,基本已经是业内常识,这些基础为后面更加精度化的优化做了很好的铺垫。 再来说一下开发方式,我们把开发方式分为服务端输出数据方式和接口渲染方式,用户浏览环境分为浏览器访问和内嵌客户端访问,不同的开发方式和访问环境优化方式略有不同,而且确实可以对页面产生一些影响

开发方式对优化的影响:

  • 服务端输出数据方式

所谓的服务端输出数据方式就是页面的 html 源码包含了页面所有的数据,这种方式开发的页面我们做了一些性能测试,结论是在浏览器环境下访问的性能不如内嵌客户端性能好,这说明了客户端 webview 对大量 html 文本的缓存能力要优于第三方浏览器,于是在一段时间内我们都是采用了这种方式开发页面,并且逐渐做成了首屏数据服务端输出,首屏以外数据接口渲染。

这种方式在很长一段时间都是比较平稳的优化方案,并且现在还在使用。但这种方式存在一些问题,因为 html 源码的增加导致文档大小变大,在弱网络环境下白屏时间会变长,为了解决这个问题,找到优化的折中点,我们尝试了接口数据渲染开发方式。

  • 接口数据渲染方式

我们把 html 看做一个模板,只有静态的数据容器,所有的动态数据调用第三方接口利用 js 渲染成页面,同样我们针对这种方式做了一些性能测试,结论是在浏览器环境下访问的性能优于内嵌客户端,这间接说明了手机独立浏览器对接口请求速度和js渲 染的处理能力要优于客户端 webview 方式。

根据这个结论我们做了一些调整优化,在客户端内不使用 webview 的 XMLHttpRequest 方式请求接口,而是使用客户端提供的原生方式请求接口,突破了 webview 线程少的限制,并提高了请求效率。

同时因为页面是一个静态模板容器,可以把页面引用的静态资源打成 zip 包动态更新至客户端,并支持增量更新的能力,当页面模板或者模板内引用的静态资源改变时,客户端会提前下载增量包,html 模板和内嵌的静态资源会提前通过客户端下载到本地,用户访问页面时就会从本地获取加载资源,极大的减少了白屏的概率。

目前我们在尝试移动端和 PC 端同样业务同样接口两个版本的同构方案,在兼顾移动端性能的同时也能兼顾 PC 端,毕竟只考虑移动端有一定的局限性。

4. 大促问题

对于电商公司来说,每一次大促就相当于一场战役,不但是业务实力的比拼,也是技术实力的比拼。每一次大促期间接到的投诉是平时的很多倍,页面加载慢 的问题在大促期间是经常被投诉的一个问题,为了减少投诉更好的提升用户体验,除了上面所提及的一些优化方案,针对大促我们还做了一些其他优化。

  • 削峰减谷

每到大促期间 CDN 流量都会飙升的很快,峰值很高,而大促预热期间的流量远不如大促当天高,如果能把大促当天的一些 CDN 静态资源流量提前到大促前几天加载,那么 CDN 流量的峰值就会被降低,而且提前缓存一些资源也会使大促当天页面加载速度变快。

为了解决这个问题,在内嵌客户端页面我们采用了上面提到的静态资源缓存机制,提前在 WIFI 环境下就把大促主会场页面所用到的静态资源下载到用户本地,大促当天开放主会场页面地址,用户即使在 2G 网络下打开页面也会很快加载静态资源,减少了很大一部分用户的白屏等待时间,同时降低了大促当天的 CDN 峰值。

客户端提前下载静态资源包方案不能适用于所有的页面,如果大量的客户端内嵌页面都采用此方案,则客户端打开的时候会下载很多静态资源包,这会影响客户端首屏加载速度,目前我们只在一些核心页面采用了此方案。

在非客户端环境同样也可以做到类似的效果。我们使用本地存储来增强浏览器的离线缓存机制,我们把 js 和 css 缓存到 localstorage 里,大促预热期提前把一些大促期间的公共静态资源提前存储到 suning.com 域名下的本地存储里,这样大促期间会有一部分人的浏览器已经提前缓存了静态资源,当第二次打开使用此方案的页面,就会优先从本地存储拉取资源。这里有一个矛盾点,本地存储的拉取渲染速度和浏览器本地缓存 304 的速度哪个更快,由于我们需要减少大促当天 CDN 的流量,综合评估下还是采用了本地存储方案。

  • 兜底防灾

一般情况下只要 CDN 稳定,即使服务端因为压力过大出现了问题静态资源也是可以正常访问到,假如一个系统提供的接口突然因为压力过大导致无法访问,这时页面就无法给用户正确的反馈,而且用户可以很明显的看到某个区域数据加载空白。

针对这个问题首先我们把每个无依赖的接口独立开来,不会因为某个接口无法访问而阻塞其他元素的渲染;

其次针对接口我们同样做了本地存储,并根据业务需求设置了对应的本地存储时间戳,最短一小时,同一个用户在当前时间戳之内不会请求接口数据,而是从本地存储调取数据;

最后假如本地存储时间戳到期,同时接口还是无法访问,这时我们会把当前区域的内容隐藏掉,让用户无法感知到这个区域没有数据加载,从而让用户没有疑惑的继续访问页面。

5. 性能监控

没有数据的性能优化都是摸着石头过河,一些方案都是根据监控数据来针对性的解决。针对大促我们专门做了一些监控有关的事情。

目前我们可以监控到具体哪些城市节点访问比较慢,页面请求时首包的峰谷波动是否稳定,同一个页面客户端和浏览器性能对比等。

下图是 418 某个时间节点某个页面的性能分布统计图,我们可以较为清晰的看到一些城市的访问不是太理想,于是会猜测排查是否某个节点的 CDN 出现了问题,然后可以采取相应的措施,而不是等用户去反馈问题后再去解决问题。

enter image description here

下图是某个 418 大促有关页面在某个时间段,首屏之前请求状态的折线图,对于一些峰值我们同样会找到是哪个城市什么网络环境出现了问题,是偶发还是必现,根据数据分析到底是哪个环节可能出现了问题。

enter image description here

下图是 418 大促期间主会场页面的数据,经过优化页面大部分的用户在访问的时候首屏都会在一秒内打开。

enter image description here

我们还做了更多更细致的监控,对应不同网络的前端性能对比,客户端内嵌和浏览器访问性能的对比,一是为了知道页面前后优化的效果对比,还有就是可以随时发现问题排查问题,更精确的定位问题。

6. 总结

前端性能优化这件事情是一个长期的过程,并且需要大量的实践和数据来证明优化方案可行,我们在开发过程中总结了一些优化方案,虽然可能不是最优解, 但是确实在实际项目中起到了很好的效果。如果每个开发人员有性能优化的意识,其实后期并不需要太刻意的优化,而一些更好的方案也会在整体性能优化意识普及的前提下不断冒出来,从而更好的提升页面性能,更好的提升用户体验。

Q&A

1、问:使用的是单 Webview 的方式还是多 WebView 的方式?具体的更新策略可以说一下吗?例如说,当打开业务时,是先下载离线资源再打开 Webview 还是打开 Webview 的同时下载离线资源,再下一次进入业务时,再使用新资源? 朱海源:根据业务决定是单 webview 还是多 webview,一般是两个以内; 先下载离线资源,我们会判断资源包的大小,低于 100kb,3g、4g、WIFI 环境启动下载,超过 500KB WIFI 环境下才会下载。

2、问:这跟我们工作内容类似,请问你们PC兼容到IE几?针对IE有些什么特别方法? 朱海源: IE 兼容这个我们是 IE7+,对于 IE 确实没有太好的办法,代码尽量写标准些,实在不行就用一些 hack,毕竟现在大家都开始基于 webkit 开发了,IE 还是别接触太多的好。

3、问 :把数据缓存到本地 最短的是一个小时,那数据不是实时更新了? 朱海源:这要看业务需求了,有的列表数据确实更新不频繁,实时去取的话很多都是无谓的性能和流量消耗。有些数据必须要实时去取,比如点赞数据,这种要是缓存的话就是生产事故了。

4、问:webview表现行为在android各个机型上面不一样,个别机型还有bug 这个怎么解决优化? 朱海源:以我们的经验,其实很多时候还是代码写的不标准,我们是这么定义测试的,如果这台手机里的 webview 有问题,那么看这台手机的 UC 或者 QQ 甚至其他浏览器是否有同样的问题,如果有,那么这个 bug 我们认为是需要修复的,如果其他浏览器没有问题,只是 webview 有问题,那么就要评估这个 bug 对业务的影响,然后觉得是否修改。其实绝大多数问题都是可以解决或者规避的。

5、问:苏宁易购的客户端,整个只有一个离线包,还是每个业务有自己的离线包? 朱海源:分为公用资源离线包和对应业务离线包,不止一个,因为不同业务线包合并确实不太好处理。

6、问:你们都是调用的系统自带的webview吗?Android低端机webveiw性能低下是怎么处理的? 朱海源:iOS 系统自带,安卓使用的第三方内核。对于安卓低端机 webview 性能低下除了一些 css3 动画会消耗性能,还有就是大量接口请求,硬件突破不了的话只能从业务层和代码层去优化。我们一般是先优化代码,效果不明显再去跟产品谈,然后再找折中方案,或者放弃这部分用户。

7、问:假设webview和native交互接口升级,为维护历史版本可用,版本控制会很多,多个业务线如何管理web代码? 朱海源:这和前端公共组件维护是一个道理,多版本并存,最新的版本的地址统一,其他根据版本选择调用。