15年双11手淘前端技术巡演 - H5性能最佳实践
Tancy opened this issue · 83 comments
前言
2015年是全面『无线化』的一年,在BAT(财报)几家公司都已经超过50%的流量来自移动端,这次 双11
更是占到了68.67%无线交易 (天猫微博)。
手淘中大量的业务采用H5的方式开发,H5体验好坏全面影响着手淘的使用体验。
今年手机淘宝在技术上重点解决“顿”,“卡”,“慢”的问题,并提出了“521法则” ,具体指:
- App内存节省50%
- 绘制帧率,滑动体验提升20%
- App全链路实现 1S 法则
- 强网(4G/Wifi)实现1S首屏(包括图片)加载
- 3G 1S首包返回
- 2G 1S建连,并且实现高复用 从底层到前端
其中1S加载完成是H5页面需要解决的重点问题,也是难点。
下面给大家介绍我们1年多来解决了些什么样的问题,以及带来多少性能的提升。以下每一条都是手淘在无线领域获得的宝贵经验。
系统&网络环境(手淘2015)
首先给大家介绍一下目前手淘的环境情况(供大家在设备兼容方面参考)。
操作系统
操作系统方面iOS占比42.23%,Android 占比52.38%,阿里云OS 占比5.29%,Windows Phone 占比 0.1%。
iOS版本 & Android版本
iOS 系统版本占比情况:
- iOS 9 49%
- iOS 8 38%
- iOS 7 11%
Android 系统版本对比iOS 碎片化较为严重,所幸4.0以下版本占比小于10%。
占比如下:
- 4.4.4版本30%
- 4.4.2版本16%
- 4.3版本11%
- 4.2.2版本10%
- 5.0版本以上10%
网络情况
网络情况方面,得力于近年的3G/4G推广已经占35%,2G网络占比15%左右。
运营商
运营商方面 **移动占据70%的用户,**联通18.12%,**电信11.69%。其中需要注意的是移动3G技术(TD-SCDMA)性能差设备支持少,移动4G容易在信号不理想的地段降级成2G。
收集性能数据&建立衡量标准
淘系H5页面主要在手淘客户端中展现,为了了解H5页面在客户端中的性能表现,我们在WebView容器中做了大量性能数据的采集,以页面,数据接口,单个静态资源为维度采集。
H5页面:我们以WebView的DidFinishLoad事件触发作为完成加载(Fully Loaded)的时间。
同时对支持performance.timing的设备收集Timing数据,用于详细分析网络请求各阶段的性能消耗情况。
WebViewDidFinishLoad 官方解释:Sent after a web view finishes loading a frame. [Android](http://developer.android.com/reference/android/webkit/WebViewClient.html#onPageFinished%28android.webkit.WebView, java.lang.String%29) iOS
1年前H5性能状况
针对几个主要的业务,我们将收集到的用户性能数据整理后得到以下的结果(部分业务按传统的网页性能优化方法优化过)。
性能情况非常不理想,不达标严重。2G下大于10s的占比在50%, 3G:6s内的低于70%近一半。
传统优化
看到上面的性能情况,我们最先想到的优化方法就是PC时代YAHOO 23条web性能优化军规。
首先看看我们日常业务的请求瀑布图是怎么样的,根据这些情况看那些可以用规则去优化。
请求数优化
- 在请求数控制方面,将js,css各用combo的方式合并成单个资源。
- 页面图片等等,只加载首屏资源,提升首屏展示速度。
- 使用CSS ,SVG,ICONFONT 替换UI图片
合理使用IconFont
iconfont对于前端来说有很多优点:自由变化大小 矢量不失真、自由修改颜色、可以添加一些视觉效果如 阴影、旋转、透明度、兼容IE6。
使用现状
目前大家都基本上从平台上生成,生成后的文件如下:
@font-face {
font-family: "iconfont";
src: url('iconfont.eot'); /* IE9*/
src: url('iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('iconfont.woff') format('woff'), /* chrome、firefox */
url('iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
url('iconfont.svg#iconfont') format('svg'); /* iOS 4.1- */
}`
这样直接引用在项目中,真实在手机上的网络请求如下(在桌面版Chrome浏览器网络中无法看到这些请求):
这样造成了极大的网络带宽的消耗,这些icon资源往往在界面渲染中占据重要位置。
目前我们移动端只加载ttf一个字体文件,对于较小的文件也可以考虑base64在css文件中。
首屏多个动态接口合并请求
日常的业务中,一个页面往往拆分出多个异步数据接口(后端开发说:解耦),甚至首屏也需要3-5个接口(如动态banner区块,推荐内容,商品列表等),有些还有嵌套关系。
但是这些对页面性能造成不小的影响。
手淘中某个接口在各网络下的请求性能,2G,3G下平均的消耗时间在2-6s完成下载。其中几个请求性能稍差点对整个页面影响也深远。
禁止重定向
在我们CaseByCase的分析中发现,页面&静态资源的重定向会造成巨大的性能损耗。
特别使用前端JS脚本来实现页面跳转的。
图片优化
手淘的特点就是图片多,图片的性能好坏可不仅仅影响用户体验哦,还直接影响着交易,钱 钱 钱…
我们在图片方面做了大量的优化。
使用WebP格式。
手淘2年前已经开始使用WebP格式了(主要native使用),1年前H5全面使用,其中iOS 的webview中由手淘以插件的方式支持。我们以手淘线上真实案例来看使用webp格式的前后效果。
案例为:线上的一个活动页面,打开一看其中的banner 就320多KB,整个页面加载457KB,如果就单单banner图片换成webp格式,整个页面的大小就只有181KB。
使用WebP前
使用WebP后
Banner部分对比
这种业务类型的案例,我们改进一下就可以为用户,为公司省70%
的流量费用。
商品图片优化
商品图片在手淘的各个产品中都是必不可少的,为了适应不同业务需求的需要,我们在CDN服务上生成各个尺寸和质量的图片(近100个规格)。
- q值:根据手淘网络情况,加载不同质量的商品图片(q30,q50,q75,q90)
- 锐化:根据需要调整图片锐化值
- DPI:根据设备DPI取适当尺寸商品图片
- 合理的使用CDN图片尺寸可以带来下载图片的性能提升,还可以减少不必要的内存消耗。 我们日常中会用到的尺寸,每浪费10像素的宽高都可以造成很大的内存资源浪费。
计算方式如下:
图片DPI 优化
根据设备DPI值和图片质量Q值做优化,达到最优视觉体验和加载性能(DPI高,宽高增加后可适当降低质量)。
Sprite图片
Sprite图片(又称:雪碧图)被运用在众多使用了很多小图标的网站上。相对于把每张小图标以单个文件的形式引用到页面上,Sprite图片会只要请求一张图片就够了,减少了请求数提升了加载性能,还有就是方便图标管理。但在移动互联网时代在使用Sprite图片需要合理利用,不然反对性能造成影响。
解码内存消耗
Decoded in memory的计算公式: w x h x 4(宽 x 高 x 每个像素4个字节)
如果设备DPI大于1,还需要 X DPI系数。如Retina设备X 4,RetinaHD设备X 9.
禁止生成大图且利用率少
由于图片在浏览器中的解码方式,合理的生成紧凑的Sprite图片,即可以带来更少的请求数,又高性能低消耗。
建议合并成如下:
不建议合并成如下:
结合Native优化
经过几轮的常规前端性能优化后,页面性能有进步,但是离目标还远远不够。我们也不断的问自己到到底那里慢,那里瓶颈最大。我们开始试着CaseByCase的分析页以及梳理H5在手淘中的全链路性能消耗。
最终做了一些和native结合的优化思路。
HTTPDNS
DNS解析想必大家都知道,在传统PC时代DNS Lookup基本在几十ms内。而我们通过大量的数据采集和真实网络抓包分析(存在DNS解析的请求),DNS的消耗相当可观,2G网络大量5-10s,3G网络平均也要3-5s。
案例:iPhone5s 联通3G
针对这种情况,手淘开发了一套httpdns,httpdns是面向无线端的域名解析服务,与传统走UDP协议的DNS不同,httpdns基于HTTP协议。 基于HTTP的域名解析,减少域名解析部分的时间并解决DNS劫持的问题。
手淘httpdns服务在启动的时候就会对白名单的域名进行域名解析,返回对应服务的最近ip(各运营商),端口号,协议类型,心跳 等信息。
优点
- 防止域名劫持
传统DNS由Local DNS解析域名,不同运营商的Local DNS有不同的策略,某些Local DNS可能会劫持特定的域名。采用httpdns能够绕过Local DNS,避免被劫持;另外,httpdns的解析结果包含HMAC校验,也能够防止解析结果被中间网络设备窜改。
- 更精准的调度
对域名解析而言,尤其是CDN域名,解析得到的IP应该更靠近客户端的地区和运营商,这样才能有更快的网络访问速度。然而,由于运营商策略的多样性,其推送的Local DNS可能和客户端不在同一个地区,这时得到的解析结果可能不是最优的。httpdns能够得到客户端的出口网关IP,从而能够更准确地判断客户端的地区和运营商,得到更精准的解析结果。
- 更小的解析延迟和波动
在2G/3G这种移动网络下,DNS解析的延迟和波动都比较大。就单次解析请求而言,httpdns不会比传统的DNS更快,但通过httpdns客户端SDK的配合,总体而言,能够显著降低解析延迟和波动。httpdns客户端SDK有几个特性:预解析、多域名解析、TTL缓存和异步请求。
- 额外的域名相关信息
传统DNS的解析结果只有ip,httpdns的解析结果采用JSON格式,除了ip外,还支持其它域名相关的信息,比如端口、spdy协议等。利用这些额外的信息,APP可以启用或停止某个功能,甚至利用httpdns来做灰度发布,通过httpdns控制灰度的比例。
SSL+SPDY协议
在经过以上的优化方案后,H5页面的性能始终离目标还远。在移动端建连的消耗非常大,在业界也只有SPDY 这个玩意儿比较新颖。
理论上SPDY协议可以完成多路复用的加密全双工通道,显著提升非wifi环境下的网络体验。
- 多路复用请求优化
- 服务器推送技术
- SPDY压缩http头
看着很牛逼的技术,但是等我们第一期上线后发现,从数据上几乎察觉不了变化。
域名收敛
域名收敛是指尽量控制一个页面中使用的域名数量。为什么要这么做呢?我们前面提到DNS解析,减少域名数量可以降低DNS解析的成本。上文还提到SPDY协议,其中一个特性就是复用请求,使用同一个域名可以更多的复用请求。这个PC时代正好相反,我们原先用多个域名提升并发请求量已提升性能。
PC时代的域名数量类似这样的
域名最终形态(建议)
- 页面请求 域名一个
- 静态资源(css,js) 一个
- 图片资源 一个
- 动态数据一个
- 数据统计一个
最终结合SSL+SPDY+域名收敛 才发挥出真正的作用。下图是各网络下SSL 和 非SSL 的性能情况。
动态数据复用状态
动态数据部分,相信各个公司都差不多,动态数据会有专门的API提供出来。手淘(mtop平台)也一样,接口总会有各种状态,登录失效,令牌过期,签名失效等。手淘使用了重发请求的方式来获取新的签名令牌等。导致如下的情况(始料未及):
在手淘真实环境中发现一次令牌过期,可以造成10多秒的延迟。
手淘在启动的时候Native已经做了很多的数据请求,这些也是mtop请求,只是由native程序发出。 我们判断到页面是在手淘客户端中就会使用native发出mtop数据请求,这样就规避了令牌失效,签名失效的问题。
直本次优化后,我们第一次看到了非常激动人心的数据:第一次里程碑式的提升
优化前
优化后
预加载和离线化方案
手淘中加载H5页面的首屏白屏时间较长,基于此,集团各BU都内部产生了离线包的方案(手淘,航旅,钱包),将静态资源通过Hybrid的方式提前加载到本地。大量了资源预加载给H5页面带来了极大的提升,资源加载时间降到30ms内。
今年双11前,针对预加载方案,在技术上解决了3个痛点
- 开发成本(开发方式侵入性强)
- 静态资源解Combo
- 更新到达率
关于 预加载&离线化方案详细技术细节很多,这里先简单阐述这个功能带来的性能提升价值。
下图案例:
- 第一个HTML没有预加载,阻塞页面时间较长
- 静态资源部分几ms 级别加载,加载性能非常好
这是第二次里程碑式的提升,3G,4G,WIFI网络性能全面提升。
截至到这个时间点为止,我们个别业务的性能有了显著的提升。以下是其中一个业务的3个性能优化节点的性能优化对比。其中10s以上加载完成的占比大大的缩小,1s以内的占比上升较高。
统计方案优化
业务数据统计在日常工作中是必不可少的部分,因统计部分量级不大,往往会忽视掉。其中我们对一个业务CaseByCase的分析后发现。一个**移动 2G/3G.Edge的用户在请求H5页面的时候 log.mmstat.com 的日志埋点花了近6s
才加载完成。
后面我们对数据统计部分做了Native的异步上传。效果是这样滴:
iOS:
Android:
第三次里程碑式的提升,2G网络性能全面提升
渲染优化
- 禁止使用iframe (阻塞父文档onload事件)
- 禁止使用GIF图片实现Loading 效果 (降低CPU消耗,提升渲染性能)视频。
业务效果
前面说了这么多性能优化,肯定会有问,花了这么多力气,前端到客户端到后端搞了这么多,价值在那里呢。业界google,amazon,microsoft都给过速度性能对业务对GMV的影响。
下面是两个手淘中的业务在持续几个月的性能优化后UV,跳失率,停留时间的变化。
2015 双11 战绩
好了,说了这么多这次双11搞的怎么样呢?
在无线时代,H5页面中的任意一个微小的点都会应网络问题被放大N倍。持续分析用户真实数据和CaseByCase的分析不同业务场景,才能真正找到性能瓶颈。
H5要达到极致的体验,需要大家跳出前端的圈子,从客户端,后端 一起的角度来共同协助发挥各自的优势才能真正做到极致的体验。后面有更多精彩等这大家。
沙发,最大的感触是“性能的问题,从10做到1,和从1做到0,是两个概念”
留名
有个问题
performance.timing 是只收集IOS9+ 和android 4.1+的用户吗?
叼叼叼
typo 负责任 -> 负责人
感谢分享,棒棒哒
赞
赞
赞赞赞
这个屌。 不过这种跨端的优化方案真的不是一般的公司所能做到的
想请问下,手淘svg方面的实践
@senyawang 确实,融合naitve的能力才能发挥到极致。这个其实也是一个信号,就是我们以前只关注浏览器端的现在在移动端是远远不够的。
这个不错,希望改一下文章里的错别字。
@Justforfei 关于SVG 的我们团队用的不是特别多。不过我们整理过一份优缺点,你可以参考一下:#2
赞!
学习了
感谢分享
SDPY协议在IOS下的支持是手淘自己实现的吗
大神啊,都已经研究到这种地步了。
叼叼叼
不错!
赞!
感谢分享,特别赞
不错,学习!
赞
有发现很多不同的角度
赞
good
nice
👍
👍
@AsiamCn 前面有个介绍android的整体情况,主要还是Android碎片化比较严重性能参差不齐。 这个地方的小于1s的占比,是各自网络段的对比,不同网络的采样率也不一样。
👍
感谢分享
技术支持得不少啊~学习了,。
@Tancy 谢谢~ 另外想请问下,手淘的项目已经全面使用flexbox了么?因为最近在对公司内部一个项目进行重构,关于图片方面的优化也在参考阿里的一些实践,学到了好多,
👍
厉害!!!
66666666
学习了,感谢分享~
一项新的技术能让你优化1ms, 发现程序中的bug和不合理的地方,能优化1s
真是厉害,学习一下在自己的项目中去结合运用一些,感谢感谢~
大赞, 羡慕你们的魔兔
点个赞,学习到不少东西。感谢。
有两个问题请 @Tancy 给回复下:
1)网络类型居然有 10.75% 的是 UNKNOWN ? 都比 2G 和 2G/3G 类型加起来的多,这块统计的依据是 RTT 时间,还是?
2)“最终结合SSL+SPDY+域名收敛 才发挥出真正的作用。下图是各网络下SSL 和 非SSL 的性能情况。”
的配图不太合理吧,不管 SSL 的状态是 “0”,还是 “1” 后面的协议全走 HTTP ?
感觉就是能交给native层的就交给native层去做,大多数优化项都与native有关
@0x7E
1). 网络类型我们通过系统CTTelephonyNetworkInfo(iOS)和ConnectivityManger(Android)获取,对其中的(Edge,GPRS,HSDPA,HSUPA,eHRPD,WCDMA,CDMA1X,CDMAEVDORev0,CDMAEVDORevA,CDMAEVDORevB,LTE,1xRTT,IDEN,UMTS)进行了识别,其他的都是UNKNOWN.
2).这个图描述的不够严谨,是报表的展示的描述问题。SSL是1的情况就是走了HTTPS的。
学到很多啊,赞!
想问一下httpDNS是怎么运用到webview里面的。是Native app 给所有webview里面请求设置代理吗?谢谢:)
能否详细讲一下httpDNS ?和传统dns的不一样在哪里?
@steelli 传统dns受制于运营商的dns解析,容易被污染。httpDNS是通过http协议来解析DNS。具体可看这个http://www.tuicool.com/articles/7nAJBb :)
webp格式ios目前还不支持,还是用png,jpg代替么,Android4.3支持不错
怒赞!
@git-patrickliu Native 托管网络请求将名单内的域名替换成IP的形式访问资源。
@xiaowtz native其实已经很多年前就已经使用了webp格式。用了webp的lib库做解码。
iOS中的请求由网络层托管,将请求的webp格式的图片获取到后转码成jpg提供给webview。
你好,可以转载你的文章吗?我们会注明作者、出处。我们将转载在这里:http://www.cheng95.com/news?cid=5
目前在公司碰到一堆H5性能问题,要解决还是要向手淘学习好的解决方案。
测试方法:
链接1: http://image-demo-hangzhou.img-cn-hangzhou.aliyuncs.com/example.jpg
链接2: http://image-demo-hangzhou.img-cn-hangzhou.aliyuncs.com/example.jpg@100p.webp
分别用上面的链接做二维码
用手淘 iPhone 5.6.0 扫一扫, 链接1可以出来图片, 链接2直接是空白的.
我是手淘互动应用的 ISV, 我们的网页里用了很多 png 图片,都是转成 webp 的, 所以对这个很敏感.
@signer 是这样的,iOS中webview本身不支持webp格式的。手淘中的实现是交给图片库来完成这部分工作(获取webp格式文件转码成jpg给webview)。你测试的图片地址不在图片库的域名范围,所以才会显示空白。
原来如此, 这个域名范围是可配置的吗? 我可以和小二申请加入白名单吗?
多谢,明白了
离线包的方案很不错,对性能提升具有很显著的效果。
我这有个问题:
- 离线包打包大小是否有限制,html css js文件都离线还是部分
- 如何处理离线包的更新呢?增量更新还是用户重新下载整个包
- 离线包有大小限制一般单个包的体积控制在1MB。可以所有文件都离线,这部分看业务需求。
- 包更新手淘有一整套解决方案(消息推送)。手淘目前的更新效率可以做到第一小时95%甚至更高和一天97%甚至更高。支持增量和全量更新。
- 针对增量的问题,我们对包也有些划分,分为基础库(相对更新频率低),和业务js包。
如何统计访问网络是什么类型的?
阿里云os威武...居然有 5%
H5是以后一个大的发展方向
👍!很全面的总结,今年有weex的加入整体速度应该会有不小提升~
图片的大小,q值,是怎么管理的?都是使用的地方自己拼接?
关于webp的请教 ,我抓包请求下来的 淘宝网站 都不是webp 还是jpg格式的图片??现在淘宝项目不是用webp了吗,是全部是用webp还是只有一部分用webp?