快捷导航
打印 上一主题 下一主题

淘宝首页性能优化实践

[复制链接]
查看: 2056|回复: 18

该用户从未签到

1

主题

32

帖子

407

积分

积分
407
跳转到指定楼层
楼主
发表于 2018-11-6 06:22:35 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多淘宝商家,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x



想必许多人都已经看到了新版的淘宝首页,它与以往不太一样,这一版页面中到处弥散着个性化的味道,由于独特的个性化需求,前端也面对各方面的技能挑衅:

  • 数据泉源多
  • 串行哀求渲染一个模块
  • 运营数据和个性化数据匹配和管理
  • 数据兜底容灾
本次淘宝首页改版,虽已不再支持 IE6 和 IE7 等低版本的古董欣赏器,但依然存在多个影响首页性能的因素:

  • 依靠体系过多,数据的哀求分为三块,其一是静态资源(如 js/css/image/iconfont 等);其二是推到 CDN 的静态数据(如运营填写的数据、前端设置信息等);其三是后端接口,差别的模块对应差别的业务,而且页面中另有不少的广告内容,大略估计页面刚加载时首屏发出的接口哀求就有 8 个,滚到最底下,得发出 20 多个哀求。
  • 无法直接输出首屏数据,首屏许多数据是通过异步哀求获取的,由于体系限定,这些哀求不可制止,而且哀求个数较多,非常影响首屏时间。
  • 模块过多,为了可以或许在背景隔离运营之间填写数据的权限,模块必须做细粒度的拆分,如下图所示:

    一个简朴的模块必须拆分成多个行业小模块,页面中其他位置也是云云,而且这些被拆分出来的模块还不必须会显现出来,必要让算法告诉前端展示哪些模块。
  • 图片过多,翻页往下滚动,很显着看到,页面整屏整屏的图片,有些图片是运营填写,有些图片由个性化接口提供,这些图片都没有固定的尺寸。
网页性能权衡指标
网页性能权衡指标有许多,倘若可以或许把握关键的几个,会合优化,性能天然也就上去了。
FPS
最能反映页面性能的一个指标是 FPS(frame per second),一样平常体系设定屏幕的革新率为 60fps,当页面元素动画、滚动大概渐变时绘制速率小于 60,就会不流通,小于 24 就会卡顿,小于 12 根本认定卡爆了。
1 帧的时长约 16ms,撤除体系上下文切换开销,每一帧中只留给大家 10ms 左右的步伐处置惩罚时间,假如一段脚本的处置惩罚时间凌驾 10ms,那么这一帧就可以被认定为丢失,假如处置惩罚时间凌驾 26ms,可以认定一连两帧丢失,依次类推。大家不能容忍页面中多次出现一连丢失五六帧的环境,也就是说必须想办法分拆实行时间凌驾 80ms 的代码步伐,这个工作并不轻松。
页面在刚开始载入的时间,必要初始化许多步伐,也或许有大量耗时的 DOM 操纵,以是前 1s 的须要操纵会导致帧率很低,大家可以忽略。固然,这是对 PC 而言,Mobile 内容少,无论是 DOM 照旧 JS 脚本量都远小于 PC,1s 或许就有点长了。
DOMContentLoaded 和 Load
DOM 加载而且剖析完成才会触发 DOMContentLoaded 变乱,倘若源码输出的内容过多,客户端剖析 DOM 的时间也会相应加长,不要鄙视这里的剖析时间,假如 DOM 数目增长 2000 个而且嵌套层级较深,剖析时间也会相应增长 50-200ms,这个斲丧对大多数页面来说实在是没须要的,包管首屏输出即可,后续的内容只保存钩子,使用 JS 动态渲染。
Load 时间可以用来权衡首屏加载中,客户端担当的信息总量,假如在首屏中布满了大尺寸图片大概客户端与后端创建毗连次数较多,Load 时间也会相应被拖长。
流通度
流通度是对 FPS 的视觉反馈,FPS 值越高,视觉出现越流通。为了保障页面的加载速率,许多内容不会在页面打开的时间全部加载到客户端。这里提到的流通度是等候过程中的视觉缓冲,如下方是 Google Plus 页面的一个结果图:

墙内访问 google 的速率不是很快,上面元素中的的许多内容都是通过异步方式加载,而从上图可以看出 Google 并没有让用户产生等候的焦急感。
淘宝首页的性能优化
由于平台限定,淘宝首页面对一个天赋的性能缺陷,首屏的渲染必要从 7 个差别的后端取数据,这些数据哀求是难以归并的,假如用户屏幕比力大,则首屏的面积也比力大,对应的后端平台数据接口就更多。数据是个性化内容大概为广告内容,故哀求也不能缓存。
关键模块优先
岂论用户首屏的面积有多大,包管关键模块优先加载。下面代码片断是初始化全部模块的中心部门:
$('.J_Module').each(function(mod) { var $mod = $(mod);
var name = $mod.attr('tms');
var data = $mod.attr('tms-data');
if($mod.hasClass('tb-pass')) { Reporter.send({ msg: "跳过模块 " + name }); return; } // 包管首屏模块先加载 if (/promo|tmall|tanx|notice|member/.test(name)) { window.requestNextAnimationFrame(function(){
// 末了一个参数为 Force, 逼迫渲染, 不懒加载处置惩罚 new Loader($mod, data, /tanx/.test(name)); }); } else { // 剩下的模块进入懒加载队列 lazyQueue.push({ $mod: $mod, data: data, force: /fixedtool|decorations|bubble/.test(name) }); }});
TMS 输出的模块都会包罗一个 .J_Module 钩子,而且会预先加载 js 和 css 文件。
对于无 JS 内容的模块,会预先打上 tb-pass 的标志,初始化的时间跳过此模块;对于首屏模块关键模块,会直接进入懒加载监控:
// $box 进入欣赏器视窗后渲染// new Loader($box, data)
->datalazyload.addCallback($box, function() {
self.loadModule($box, data);});// $box 立刻渲染
// new Loader($box, data, true) ->self.loadModule($box, data);
除必须立刻加载的模块外,关键模块被加到懒加载监控,缘故原由是,部门用户进入页面就或许急速往下拖拽页面,此时,没须要渲染这些首屏模块。
非关键模块同一送到 lazyQueue 队列,没有基于将非关键模块参加到懒加载监控,这里有两个缘故原由:

  • 一旦参加监控,步伐滚动就必要对每个模块做盘算判定,模块太多,这里或许存在性能丧失
  • 假如关键模块还没有加载好,非关键模块进入视窗就会开始渲染,这势必会影响关键模块的渲染
那么,什么时间开始加载非关键模块呢?
var __lazyLoaded = false;function runLazyQueue() {
if(__lazyLoaded) { return; } __lazyLoaded = true; $(window).detach("mousemove scroll mousedown touchstart
touchmove keydown resize onload", runLazyQueue);
var module; while (module = lazyQueue.shift()) { ~function(m){
// 包管在欣赏器空闲时间处置惩罚 JS 步伐, 包管不壅闭 window.requestNextAnimationFrame(function() {
new Loader(m.$mod, m.data, m.force); }); }(module); }}$(window).on("mousemove scroll mousedown touchstart
touchmove keydown resize onload", runLazyQueue);
// 担心未触发 onload 变乱, 5s 之后实行懒加载队列
window.requestNextAnimationFrame(function() { runLazyQueue();}, 5E3);
上面的代码应该非常清楚,两种哀求下会开始将非关键模块参加懒加载监控:

  • 当页面中触发 mousemove scroll mousedown touchstart touchmove keydown resize onload 这些变乱的时间,阐明用户开始与页面交互了,步伐必须开始加载。
  • 假如用户没有交互,但是页面已经 onload 了,步伐固然不能浪费这个绝佳的空档时机,乘隙加载内容;经测试,部门环境下,onload 变乱没有触发(缘故原由尚不知),以是还设定了一个超时加载,5s 之后,岂论页面加载环境怎么,都会将剩下的非关键模块参加到懒加载监控。
懒实行,有交互才实行
假如说上面的优化叫做懒加载,那么这里的优化可以称之为懒实行。
首页上有几个模块是包罗交互的,如头条地区的 tab ,便民服务的浮层和主题市场的浮层,部门用户进入页面或许根本不会利用这些功能,以是步伐上并没有对这些模块做彻底的初始化,而是比及用户 hover 到这个模块上再实行全部逻辑。
更懒的实行,革新页面才实行
首屏中有两个次要哀求,一个是主题市场的 hot 标,将用户最常逛的三个类目打标;第二个是个人中央的被页粳差别的都会会展示差别的配景图片,这里必要哀求拿到都会信息。
这两处的渲染计谋都是,在步伐的 idle(空闲)时期,大概 window.onload 十秒之后去哀求,然后将哀求的效果缓存到当地,当用户第二次访问淘宝首页时可以或许看到结果。这是一种更懒的实行,用户革新页面才看得到.这种优化是宝贝可以或许担当,也是技能上公道的优化本领。
图片尺寸的控制和懒加载
岂论图片链接的泉源是运营填写照旧接口输出,都难以包管图片具备适当的宽高,加上现在 retina 的屏幕越来越多,对于这种用户也要提供优质的视觉体验,图片这块的处置惩罚并不轻松。

阿里 CDN 是支持对图片尺寸做压缩处置惩罚的,为 200×200 尺寸的图片。
加上 _100x100.jpg 的参数后,会酿成小尺寸:100x100
大家知道 webp 格式的图片比对应的 jpg 要小三分之一,如上图加上 _.webp 参数后:100x100 webp
视觉结果并没有什么扣头,但是图片体积缩小了三分之一,图片越大,节流的越显着。显然,淘宝首页的全部图片都做了如上的限定,针对坑位巨细对图片做压缩处置惩罚,只是这里必要留意的是,运营填写的图片或许已经是压缩过的,如:
$img = '//g.alicdn.com/real/path/to/img.png_400x400.jpg';

上面这种环境,图片是不会精确展示的。首页对全部的图片的懒加载都做了同一的函数处置惩罚:
src = src.replace(/\s/g, '');var arr;
if (/(_\d{2,}x\d{2,}\w*?\.(?:jpg|png)){2,}
/.test(src) && src.indexOf('_!!') == -1) { arr = src.split('_');
if (arr[arr.length - 1] == '.webp') { src = [arr[0], arr[arr.length - 2],
arr[arr.length - 1]].join('_'); } else { src = [arr[0], arr[arr.length - 1]].join('_'); }}if (src.indexOf('_!!') > -1) { src = src.replace(/((_\d{2,}x\d{2,}[\w\d]*?|_co0)
\.(jpg|png))+/, '$1');}WebP.isSupport(function(isSupportWebp) {
// https 协议访问存在题目 IE8,去 schema if (/^http:/.test(src)) { src = src.slice(5); } // 支持 webp 格式,而且 host 以 taobaocdn 和 alicdn 末端
,而且不是 s.gif 图片 if (isSupportWebp && /(taobaocdn|alicdn)\.com/.test
(src) && (src.indexOf('.jpg') || src.indexOf('.png'
)) && !/webp/.test(src) && !ignoreWebP && !
/\/s\.gif$/.test(src)) { src += '_.webp'; } $img.attr('src', src);});
模块去钩子,走设置
TMS 的模块在输出的时间会将数据的 id 放在钩子上:


假如模块是异步展示的,可以通过 tms-datakey 找到模块数据,而首页的个性化是从几十上百个模块中通过算法选出几个,假如把这些模块钩子全部输出来,虽说取数据方便了许多,却存在大量的冗余,对此的优化计谋是:将数据格式雷同的模块单独拿出来,新建页面作为数据页。以是可以在源码中看到好几段如许的设置信息:
[{"backup":"false","baseid":"1","mid":"222726","name":"iFashion","per":"false","tid":"3"
,"uid":"1000"},{"backup":"false","baseid":"3","mid":"222728","name":"美妆秀","per":"false","tid":"3","uid":"1001"},{"backup":"false","baseid":"4","mid":"222729","name":"爱逛街","per":"false","tid":"4","uid":"1002"},{"backup":"false","baseid":"2","mid":"222727","name":"环球购","per":"false","tid":"4","uid":"1003"}]
淘汰了大量的源码以及对 DOM 的剖析。
低频修改模块,缓存哀求
有一些模块数据是很少被修改的,好比接口的兜底数据、阿里 APP 模块数据等,可以通过调解参数,设置模块的缓存时间,如:
io({ url: URL,
dataType: 'jsonp',
cache: true,
jsonpCallback: 'jsonp' + Math.floor(new Date / (1000 * 60)),
success: function() {
//...
}
});
Math.floor(new Date / (1000 * 60)) 这个数值在一分钟内是不会发生变革的,也就是说将这个哀求在当地缓存一分钟,对于低频修改模块,缓存时间可以设置为一天,即:
Math.floor(new Date / (1000 * 60 * 60 * 24))
固然,大家也可以接纳当地储存的方式缓存这个模块数据:
offline.setItem('cache-moduleName', JSON.stringify(data)
, 1000 * 60 * 60 * 24);
缓存逾期时间设置为 1 天,淘宝首页重要接纳当地缓存的方式。
利用缓动结果淘汰等候的焦虑感
这方面的优化不是许多,但是也有一点结果,许多模块的展示并不是干巴巴的 .show(),而是通过动画结果,缓动出现,这方面的优化保举利用 CSS3 属性去控制,性能斲丧会少许多。
优化的思索角度
页面优化的切入点许多,大家不必须可以或许八面见光,但是对于一个承载较大店铺流量的页面来说,下面几条必须有用实行:

  • 首屏必须要快
  • 滚屏必须要流通
  • 能不加载的先别加载
  • 能不实行的先别实行
  • 渐希望现、油滑显现
固然,性能优化的切入角度不但仅是上几个方面,对照 Chrome 的 Timeline 柱状图和折线图,大家还可以找到许多优化的点,如:

  • 在 1.0s 左右存在一次 painting 壅闭,或许由于一次性展示的模块面积过大
  • 从 FPS 的柱状图可以看出,在 1.5s-2.0s 之间,存在频频 Render 和 JavaScript 丢帧
  • 从多出的红点可以看出页面 jank 次数,也可以或许定位到代码堆栈
在优化的过程中必要更多地思索,怎么让壅闭的脚天职批实行,怎么将长时间实行的脚本匀称地分配到时间线上。这些优化都体如今代码的细节上,宏观上的处置惩罚难以有显着的结果。固然,在宏观上,淘宝首页也有一个显着的优化:
// http://gist.github.com/miksago/3035015#file-raf-js
(function() { var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length &&
!window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+
'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+
'CancelAnimationFrame'] || window[vendors[x]+
'CancelRequestAnimationFrame']; } if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function(
callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime
- lastTime));
var id = window.setTimeout(function() {
callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; } if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) { clearTimeout(id); }; }})();
这段代码根本包管每个模块的初始化都是在欣赏器空闲时期,淘汰了许多不须要的丢帧。这个优化也可以被应用到每个模块的细节代码之中,不外优化难度会更高。
小结
代码的性能优化是一个精致活,假如你要在一个巨大的未经优化的页面上做性能优化,或许会面对一次重构代码。本文从淘宝首页个性化引出的题目出发,从微观到宏观报告了页面的优化实践,提出了几条可以鉴戒的优化尺度,盼望对你有所开导。优化的细节点形貌的不敷美满也不敷全面,但是都是值得去优化的方向。




上一篇:怎么做好关键词优化-让关键词排名快速攀升
下一篇:淘宝优化:为何要优化标题?
这里可以随意广告或签名,发布主题后即可显示,设置方法:右上角【我的设置-个人信息-个性签名】
回复

使用道具 举报

该用户从未签到

1

主题

39

帖子

427

积分

积分
427
沙发
发表于 2018-11-15 00:54:16 | 只看该作者
楼主很优秀啊
这里可以随意广告或签名,发布主题后即可显示,设置方法:右上角【我的设置-个人信息-个性签名】
回复

使用道具 举报

该用户从未签到

0

主题

23

帖子

379

积分

积分
379
板凳
发表于 2018-12-7 15:24:39 | 只看该作者
谢谢楼主分享
这里可以随意广告或签名,发布主题后即可显示,设置方法:右上角【我的设置-个人信息-个性签名】
回复

使用道具 举报

该用户从未签到

0

主题

33

帖子

409

积分

积分
409
地板
发表于 2018-12-8 07:30:35 | 只看该作者
很不错 谢谢分享
这里可以随意广告或签名,发布主题后即可显示,设置方法:右上角【我的设置-个人信息-个性签名】
回复

使用道具 举报

该用户从未签到

1

主题

51

帖子

464

积分

积分
464
5#
发表于 2021-5-3 08:06:33 | 只看该作者
来论坛来学习淘宝知识的
这里可以随意广告或签名,发布主题后即可显示,设置方法:右上角【我的设置-个人信息-个性签名】
回复

使用道具 举报

该用户从未签到

0

主题

32

帖子

406

积分

积分
406
6#
发表于 2021-6-22 17:45:55 | 只看该作者
文章很好,学习了楼主
这里可以随意广告或签名,发布主题后即可显示,设置方法:右上角【我的设置-个人信息-个性签名】
回复

使用道具 举报

该用户从未签到

2

主题

41

帖子

433

积分

积分
433
7#
发表于 2021-6-22 18:38:54 | 只看该作者
不知道实力运用这个方法会怎么样
这里可以随意广告或签名,发布主题后即可显示,设置方法:右上角【我的设置-个人信息-个性签名】
回复

使用道具 举报

该用户从未签到

1

主题

32

帖子

407

积分

积分
407
8#
发表于 2021-6-25 14:07:21 | 只看该作者
66666666666666
这里可以随意广告或签名,发布主题后即可显示,设置方法:右上角【我的设置-个人信息-个性签名】
回复

使用道具 举报

该用户从未签到

1

主题

35

帖子

415

积分

积分
415
9#
发表于 2021-7-30 15:28:14 | 只看该作者
厉害学习到了
这里可以随意广告或签名,发布主题后即可显示,设置方法:右上角【我的设置-个人信息-个性签名】
回复

使用道具 举报

该用户从未签到

0

主题

51

帖子

463

积分

积分
463
10#
发表于 2021-8-8 18:55:24 | 只看该作者
过来学习啦 哈哈
这里可以随意广告或签名,发布主题后即可显示,设置方法:右上角【我的设置-个人信息-个性签名】
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

精彩推荐

让创业更简单

  • 反馈建议:admin@tao92.com
  • 工作时间:周一到周五 10:00-19:00
  • 淘九二电商网祝您店铺火火火!!!

云服务支持

精彩文章,快速检索

关注我们

Copyright   ©2015-2016  淘宝卖家开店运营论坛_淘宝卖家经验交流学习社区  Powered by©Tuyuanma  技术支持:tao92