1. 性能分析:
1.1 页面加载性能
加载时间,用户体验
1.2 动画与操作性能
是否流畅无卡顿
1.3 内存占用
内存占用过大,浏览器崩掉等
1.4 电量消耗
游戏方面,暂不考虑
2. 性能优化从以下几个方面考虑:
2.1.对加载时所消耗的网络资源优化(网络优化)
1. 减少http请求(精灵图、文件的合并)
2. 减小文件大小(资源压缩、图片压缩、代码压缩)
3. CSN(第三方库,大文件,大图)
4. SSR服务端渲染、预渲染
5. 懒加载
6. 分包
7. 缓存以及Ajax缓存
8. 资源预加载
9. 中间件
2.2.资源加载完后,脚本解释执行的速度(代码优化)
1. 减少dom操作,避免回流,文档碎片
2. 摇树优化,清除无用代码
3. 算法复杂度
4. 逻辑后移
5.将样式表放在顶部,将脚本放在底部,减少重绘,按需加载,模块化
2.3 选择性能较好的框架,比如[benchmark]([https://link.zhihu.com/?target=https%3A//stefankrause.net/js-frameworks-benchmark8/table.html](url))(框架优化)
3. 性能优化详情
3.1 tree shaking(摇树优化,清除项目中无用代码,引用第三方库注意导入方式)
中文(摇树),webpack构建优化中重要一环。摇树用于清除我们项目中的一些无用代码,它依赖于ES中的模块语法。
比如日常使用lodash的时候
import _ from 'lodash'
如果如上引用lodash库,在构建包的时候是会把整个lodash包打入到我们的bundle包中的。
import _isEmpty from 'lodash/isEmpty';
如果如上引用lodash库,在构建包的时候只会把isEmpty这个方法抽离出来再打入到我们的bundle包中。
这样的化就会大大减少我们包的size。所以在日常引用第三方库的时候,需要注意导入的方式。
如何开启摇树
在webpack4.x 中默认对tree-shaking进行了支持。 在webpack2.x 中使用tree-shaking:传送门
3.2 split chunks(分包)
中文(分包)
在没配置任何东西的情况下,webpack 4 就智能的帮你做了代码分包。入口文件依赖的文件都被打包进了main.js,那些大于 30kb 的第三方包,如:echarts、xlsx、dropzone等都被单独打包成了一个个独立 bundle。
其它被我们设置了异步加载的页面或者组件变成了一个个chunk,也就是被打包成独立的bundle。
它内置的代码分割策略是这样的:
- 新的 chunk 是否被共享或者是来自 node_modules 的模块
- 新的 chunk 体积在压缩之前是否大于 30kb
- 按需加载 chunk 的并发请求数量小于等于 5 个
- 页面初始加载时的并发请求数量小于等于 3 个
大家可以根据自己的项目环境来更改配置。配置代码如下:
splitChunks({
cacheGroups: {
vendors: {
name: `chunk-vendors`,
test: /[\/]node_modules[\/]/,
priority: -10,
chunks: 'initial',
},
dll: {
name: `chunk-dll`,
test: /[\/]bizcharts|[\/]@antv[\/]data-set/,
priority: 15,
chunks: 'all',
reuseExistingChunk: true
},
common: {
name: `chunk-common`,
minChunks: 2,
priority: -20,
chunks: 'all',
reuseExistingChunk: true
},
}
})
没有使用webpack4.x版本的项目,依然可以通过**按需加载**的形式进行分包,使得我们的包分散开,提升加载性能。
按需加载也是以前分包的重要手段之一
这里推荐一篇非常好的文章:webpack如何使用按需加载
3.3 拆包
与3.2的分包不同。大家可能没发现,上面2.3的bundle包解析中有个有趣的现象,上面项目的技术栈是react,但是bundle包中并没有react、react-dom、react-router等。
因为把这些插件“拆”开了。并没有一起打在bundle中。而是放在了CDN上。下面我举一个例子来解释一下。
假设:原本bundle包为2M,一次请求拉取。拆分为 bundle(1M) + react桶(CDN)(1M) 两次请求并发拉取。
从这个角度来看,1+1的模式拉取资源更快。
换一个角度来说,全量部署项目的情况,每次部署bundle包都将重新拉取。比较浪费资源。react桶的方式可以命中强缓存,这样的化,就算全量部署也只需要重新拉取左侧1M的bundle包即可,节省了服务器资源。优化了加载速度。
注意:在本地开发过程中,react等资源建议不要引入CDN,开发过程中刷新频繁,会增加CDN服务其压力,走本地就好。
3.4 gzip(服务端配置gzip压缩)
服务端配置gzip压缩后可大大缩减资源大小。
Nginx配置方式
http {
gzip on;
gzip_buffers 32 4K;
gzip_comp_level 6;
gzip_min_length 100;
gzip_types application/javascript text/css text/xml;
gzip_disable "MSIE [1-6].";
gzip_vary on;
}
配置完成后在response header中可以查看。
3.5 图片压缩
开发中比较重要的一个环节,我司自己的图床工具是自带压缩功能的,压缩后直接上传到CDN上。
如果公司没有图床工具,我们该如何压缩图片呢?我推荐几种我常用的方式
图片压缩是常用的手法,因为设备像素点的关系,UI给予的图片一般都是 x2,x4的,所以压缩就非常有必要。
3.6 图片分割
如果页面中有一张效果图,比如真机渲染图,UI手拿着刀不让你压缩。这时候不妨考虑一下分割图片。
建议单张土图片的大小不要超过100k,我们在分割完图片后,通过布局再拼接在一起。可以图片加载效率。
这里注意一点,分割后的每张图片一定要给height,否则网速慢的情况下样式会塌陷。
3.7 sprite(精灵图)
南方叫精灵图,北方叫雪碧图。这个现象就很有趣。
在网站中有很多小图片的时候,一定要把这些小图片合并为一张大的图片,然后通过background分割到需要展示的图片。
这样的好处是什么呢?先来普及一个规则
浏览器请求资源的时候,同源域名请求资源的时候有最大并发限制,chrome为6个,就比如你的页面上有10个相同CDN域名小图片,那么需要发起10次请求去拉取,分两次并发。第一次并发请求回来后,发起第二次并发。
如果你把10个小图片合并为一张大图片的画,那么只用一次请求即可拉取下来10个小图片的资源。减少服务器压力,减少并发,减少请求次数。
附上一个sprite的例子。
3.8 CDN(内容分发网络,静态资源度建议放在CDN上,可以加快资源加载的速度)
中文(内容分发网络),服务器是中心化的,CDN是“去中心化的”。
在项目中有很多东西都是放在CDN上的,比如:静态文件,音频,视频,js资源,图片。那么为什么用CDN会让资源加载变快呢?
举个简单的例子:
> 以前买火车票大家都只能去火车站买,后来我们买火车票就可以在楼下的火车票代售点买了。
你细品。
所以静态资源度建议放在CDN上,可以加快资源加载的速度。
3.9 懒加载(在长网页中延迟加载图像,非常好的优化网页性能的方式)
懒加载也叫延迟加载,指的是在长网页中延迟加载图像,是一种非常好的优化网页性能的方式。
当可视区域没有滚到资源需要加载的地方时候,可视区域外的资源就不会加载。
可以减少服务器负载,常适用于图片很多,页面较长的业务场景中。
如何使用懒加载呢?
3.10 iconfont(字体图表,现在比较流行的一种用法,使用前提是有好字体图标库)
中文(字体图表),现在比较流行的一种用法。使用字体图表有几种好处
- 矢量
- 轻量
- 易修改
- 不占用图片资源请求。
就像上面说的雪碧图,如果都用字体图标来替换的画,一次请求都免了,可以直接打到bundle包中。
使用前提是UI给点力,设计趋向于字体图标,提前给好资源,建立好字体图标库。
3.11 逻辑后移(常见优化手段,在平常的开发中建议时常注意逻辑后移)
逻辑后移是一种比较常见的优化手段。用一个打开文章网站的操作来举个例子。
没有逻辑后移处理的请求顺序是这个样子的
页面的展示主体是文章展示,如果文章展示的请求靠后了,那么渲染文章出来的时间必然靠后,因为有可能因为请求阻塞等情况,影响请求响应情况,如果超过一次并发的情况的话,会更加的慢。如图的这种情况也是在我们项目中发生过的。
很明显我们应该把主体“请求文章”接口前移,把一些非主体的请求逻辑后移。这样的话可以尽快的把主体渲染出来,就会快很多。
优化后的顺序是这个样子的。
在平常的开发中建议时常注意逻辑后移的情况,突出主体逻辑。可以极大的提升用户体验。
3.12 算法复杂度(数据量大的应用场景使用)
在数据量大的应用场景中,需要着重注意算法复杂度问题。
在这个方面可以参考Javascript算法之复杂度分析这篇文章。
如上面Performance解析出的Javascript执行指标上,可以推测出来你的code执行效率如何,如果执行时间过长就要考虑一下是否要优化一下复杂度了。
> 在时间换空间,空间换时间的选择上,要根据业务场景来进行取舍。
3.13 组件渲染(没有必要的渲染是对性能的极大浪费)
拿react举例,组件分割方面不要太深。需要控制组件的渲染,尤其是深层组件的render。
老生常谈的话题,我们可以一些方式来优化组件渲染
- 声明周期控制 - 比如react的shouldComponentUpdate来控制组件渲染。
- 官网提供的api- PureComponent
- 控制注入组件的参数
- 分配组件唯一key
没有必要的渲染是对性能的极大浪费。
3.14 node middleware(中间件主要是指封装所有Http请求细节处理的方法,非常实用)
中文(node 中间件)
中间件主要是指封装所有Http请求细节处理的方法。一次Http请求通常包含很多工作,如记录日志、ip过滤、查询字符串、请求体解析、Cookie处理、权限验证、参数验证、异常处理等,但对于Web应用而言,并不希望接触到这么多细节性的处理,因此引入中间件来简化和隔离这些基础设施与业务逻辑之间的细节,让我们能够关注在业务的开发上,以达到提升开发效率的目的。
使用node middleware合并请求。减少请求次数。这种方式也是非常实用的。
3.15 web worker(传送门,为js创建多线程环境)
Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。
合理实用web worker可以优化复杂计算任务。这里直接抛阮一峰的入门文章:传送门
3.16 缓存(性能优化优先考虑---使用缓存)
缓存的原理就是更快读写的存储介质+减少IO+减少CPU计算=性能优化。而性能优化的第一定律就是:优先考虑使用缓存。
缓存的主要手段有:浏览器缓存、CDN、反向代理、本地缓存、分布式缓存、数据库缓存。
3.17 GPU渲染(有复杂的动画时使用)
每个网页或多或少都涉及到一些CSS动画,通常简单的动画对于性能的影响微乎其微,然而如果涉及到稍显复杂的动画,不当的处理方式会使性能问题变得十分突出。
像Chrome, FireFox, Safari, IE9+和最新版本的Opera都支持GPU加速,当它们检测到页面中某个DOM元素应用了某些CSS规则时就会开启。
虽然我们可能不想对元素应用3D变换,可我们一样可以开启3D引擎。例如我们可以用`transform: translateZ(0)` 来开启GPU加速 。
只对我们需要实现动画效果的元素应用以上方法,如果仅仅为了开启硬件加速而随便乱用,那是不合理的。
3.18 Ajax可缓存(请求的URL和返回的响应结果保存在缓存内,尽量使用get)
Ajax在发送的数据成功后,为了提高页面的响应速度和用户体验,会把请求的URL和返回的响应结果保存在缓存内,当下一次调用Ajax发送相同的请求(URL和参数完全相同)时,它就会直接从缓存中拿数据。
在进行Ajax请求的时候,可以选择尽量使用get方法,这样可以使用客户端的缓存,提高请求速度。
3.19 Resource Hints(资源预加载,非常好的优化方法)
Resource Hints(资源预加载)是非常好的一种性能优化方法,可以大大降低页面加载时间,给用户更加流畅的用户体验。
现代浏览器使用大量预测优化技术来预测用户行为和意图,这些技术有预连接、资源与获取、资源预渲染等。
Resource Hints 的思路有如下两个:
- 当前将要获取资源的列表
- 通过当前页面或应用的状态、用户历史行为或 session 预测用户行为及必需的资源
实现Resource Hints的方法有很多种,可分为基于 link 标签的 DNS-prefetch、subresource、preload、 prefetch、preconnect、prerender,和本地存储 localStorage。
3.20 SSR(服务端渲染,渲染过程在服务端完成,很多时候用作首屏优化、SEO(搜索引擎优化),对服务器有要求)
渲染过程在服务器端完成,最终的渲染结果 HTML 页面通过 HTTP 协议发送给客户端,又被认为是‘同构'或‘通用',如果你的项目有大量的detail页面,相互特别频繁,建议选择服务端渲染。
服务端渲染(SSR)除了SEO还有很多时候用作首屏优化,加快首屏速度,提高用户体验。但是对服务器有要求,网络传输数据量大,占用部分服务器运算资源。
Vue的Nuxt.js和React的next.js都是服务端渲染的方法。
3.21 UNPKG(一个提供npm包进行CDN加速的站点,)
UNPKG是一个提供npm包进行[CDN加速](https://cloud.tencent.com/product/cdn?from=10680)的站点,因此,可以将一些比较固定了依赖写入html模版中,从而提高网页的性能。首先,需要将这些依赖声明为external,以便webpack打包时不从node_modules中加载这些资源,配置如下:
externals: { 'react': 'React' }
其次,你需要将所依赖的资源写在html模版中,这一步需要用到[html-webpack-plugin](https://link.zhihu.com/?target=https%3A//github.com/jantimon/html-webpack-plugin)。下面是一段示例:
<% if (htmlWebpackPlugin.options.node_env === 'development') { %>
<script src="https://unpkg.com/react@16.7.0/umd/react.development.js"></script>
<% } else { %>
<script src="https://unpkg.com/react@16.7.0/umd/react.production.min.js"></script>
<% } %>
这段代码需要注入node_env,以便在开发的时候能够获得更友好的错误提示。也可以选择一些比较自动的库,来帮助我们完成这个过程,比如[webpack-cdn-plugin](https://link.zhihu.com/?target=https%3A//www.npmjs.com/package/webpack-cdn-plugin),或者[dynamic-cdn-webpack-plugin](https://link.zhihu.com/?target=https%3A//github.com/mastilver/dynamic-cdn-webpack-plugin)。
3.21 其他方法
将样式表放在顶部,将脚本放在底部,减少重绘,按需加载,模块化等