
1
首屏加载性能 首屏加载耗时,TP75从原来的2.47秒减小到了1.58秒,性能提升约36.03%。图2所示为优化前后以周为维度的首屏TP75加载时长。
2
服务器性能 通过对服务器进行压测,在相同QPS维度下,CPU从原来的29.52%降低至20.5%,CPU使用率相比之前降低了30.5%
1
Performance API
Performance API是ECMAScript5才引入的,精度可达到1毫秒的千分之一,目前主流浏览器基本都已经支持performance对象。通过performance.timing对象,可以拿到浏览器处理网页各个阶段的耗时。通过performance.getEntries方法,可以获取js, css, 图片及ajax在内的所有请求的耗时信息。 我们基于Performance API,封装了一个前端测速模块,该模块在页面加载完成后将所需性能数据上报至服务器,之后可以在可视化平台上进行数据的展示及分析。2
Chrome Devtools
Chrome Devtools是前端调试及性能分析常用的工具,通过该工具,可以查看页面资源加载情况,所加载CSS、JS及图片的大小,还可以通过Performance面板,查看页面渲染绘制和Script执行情况。3
v8-profiler
通天塔H5是基于React SSR架构的,页面首屏在Node中间层请求数据并渲染,所以除纯前端的监控及分析,还需对Node层进行性能分析及优化。在Node层性能分析中,我们主要通过v8-profiler模块进行性能分析。 在本地或测试环境下新增两个路由:const profiler = require('v8-profiler');
router.get('/profiler/start', (req, res) => {
//Start Profiling
profiler.startProfiling('CPU profile');
res.end('profile start');
});
router.get('profiler/end', (req, res) => {
const profile = profiler.stopProfiling()
profile.export()
.pipe(res)
.on('finish', () => {
profile.delete();
res.end();
});
});
通过ab压测工具,对服务器发起请求
ab -c 10 -n 1000 http://localhost:7001/mall/active/xxx/index.html
在压测过程中,可以通过 http://localhost:7001/profiler/start开始性能统计,通过http://localhost:7001/profiler/end结束性能统计,并将结果保存为 ***.cpuprofile文件,通过Chrome Devtools中的JavaScript Profiler工具进行分析。
1
前端常规优化 在优化之初,根据《高性能网站建设指南》提及的常规优化方案,我们检查了项目中需要改进或深度优化的地方,主要涉及以下方面:- 尽可能的减少HTTP的请求数,减小HTTP请求大小
- 将静态资源放在CDN,最大化利用CDN缓存能力
- 减少CSS和JS请求个数,减小CSS和JS包大小
- 启用gzip压缩

const isJfsRegex = /360buyimg\.com\/.*\/((s([\d^_]+)x([\d^_]+)_)?jfs)/i;
export function resizeImg(url, rect) {
const dpr = window.devicePixelRatio;
if (!isJpegRegExp.test(url)) {
return url;
}
const result = url.match(isJfsRegex);
if (!result) {
return url;
}
if (result[3] && result[4]) {
if (!rect || (!rect.width && !rect.height)) {
return url;
}
if (rect.width && !rect.height) {
rect.height = rect.width / result[3] * result[4];
}
if (rect.height && !rect.width) {
rect.width = rect.height / result[4] * result[3];
}
const t = 's' + Math.ceil(rect.width* dpr) + 'x' + Math.ceil(rect.height* dpr) + '_jfs';
return url.replace(result[1], t);
} else {
if (rect && rect.width && rect.height) {
return url.replace('/jfs/', `/s${Math.ceil(rect.width * dpr)}x${Math.ceil(rect.height * dpr)}_jfs/`);
}
}
return url;
}
2)最大化利用CDN缓存
在做性能优化前,通天塔静态资源的打包,是开发者在上线前,在自己电脑上进行的,且文件名会依据文件内容重新生成,格式为[filename].[contenthash:8].js。
按这种方式在个人电脑上打包,即使有package-lock.json锁定包版本,但由于个人电脑操作系统及使用的npm包管理工具的不同(有的包管理工具不读package-lock.json),node_module下的文件可能会不一致,导致文件的contenthash不同。
针对这个问题,我们基于Jenkins搭建了一个前端CI打包系统,后继所有上线前的前端静态资源打包,都迁移到CI上进行,通过这种方式,确保了文件名的一致性,以最大程度的利用CDN缓存。
3)调整webpack打包策略,按需加载CSS和JS
在性能优化前,通天塔的CSS和JS资源是按以下策略打包的:
- vendor.[contenthash:8].js: 包含node_module下的代码
- common.[contenthash:8].js: 包含非node_modules下的代码
- [channel].[contenthash:8].js: 通天塔有很多渠道,每个渠道的专属代码打包到这个JS中
- template.[contenthash:8].css: 包含所有渠道通用CSS
- [channel].[contenthash:8].css: 包含渠道专有CSS
- vendor.[contenthash:8].js: 包含node_module下的JS文件
- lowUsedTemp.[contenthash:8].js: 包含使用频率低的系统模板代码,页面会按照活动是否使用到低频模板按需请求
- mute.[contenthash:8].js: 包含剔除低频使用模板后,较为稳定,很少改动的系统模板
- template.[contenthash:8].js: 包含剩余非node_modules下的代码
- [channel].[contenthash:8].js: 包含渠道专属代码
- lowUsedTemp.[contenthash:8].css: 包含使用频率低的系统模板代码的CSS,页面会按照活动是否使用到低频模板按需请求
- template.[contenthash:8].css: 包含所有渠道通用CSS
- [channel].[contenthash:8].css: 包含渠道专有CSS
2
业务优化 在常规的前端性能优化达到瓶颈后,我们开始尝试基于业务进行性能优化。 1)首屏精准化优化 通天塔页面是运营在可视化配置平台中,通过选择模板,配置数据来动态生成的,而其中类似商品楼层这种素材楼层,配置的素材数量也由运营自己决定,少的可能只有几个,多的几十上百个,这便导致通天塔首屏页面有以下特点 1. 页面灵活多变,页面结构难以预测。 2. 在请求首屏楼层数据时,服务端难以计算需要下发几个楼层刚好满首屏,故按照素材楼层数来进行分页,如果首页素材楼层配置的素材较多,节点数会非常庞大。 由于以上两个特点,导致很多活动页首屏的内容,远大于客户端首屏实际所需展示的长度,这既加大了首屏的渲染耗时,同时也浪费了Node服务器的CPU资源(渲染了不必要的楼层)。 另外,在通过v8-profiler测试Node服务器性能时,我们发现Node服务器端开销最大的地方有三处- 通过JSON.parse解析后端下发的活动数据
- React.renderToString 进行首屏渲染
- JSON.stringify将首屏数据序列化后跟随HTML下发给客户端

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<img data-src="/img-size.png" id="test" />
<h1>我是测试代码</h1>
<script>
(function() {
var start = Date.now();
console.log('start', start)
var img = document.getElementById('test');
img.onload = function() {
console.log('end', Date.now(), Date.now() - start); // end - start > 2000ms
}
img.src = img.getAttribute('data-src');
})();
</script>
<h1>我是测试代码22222</h1>
<img src="/performance-cpu.jpg" />
<script src="/test.js"></script>
</body>
</html>
其中test.js中很简单
console.log('start');
var start = Date.now();
for(;;) {
if (Date.now() - start > 2000) {
break;
}
}
console.log('end');

声明:本文由网站用户香香发表,超梦电商平台仅提供信息存储服务,版权归原作者所有。若发现本站文章存在版权问题,如发现文章、图片等侵权行为,请联系我们删除。