05-性能优化
1. tree shaking
中文(摇树),webpack 构建优化中重要一环。摇树用于清除项目中的一些无用代码,它依赖于ES中的模块语法
// 引用 lodash 库,在构建包时是会把整个 lodash 包打入到 bundle 包中的
import _ from 'lodash'
// 引用lodash库,在构建包时只会把 isEmpty 这个方法抽离出来再打入到 bundle 包中
import _isEmpty from 'lodash/isEmpty';
- 在日常引用第三方库的时候,需要注意导入的方式
- 在 webpack4.x 中默认对 tree-shaking 进行了支持。 在 webpack2.x 中使用tree-shaking:如何在 Webpack 2 中使用 tree-shaking
2. split chunks
中文(分包)
- 在没配置任何东西的情况下,webpack 4 智能的做了代码分包。入口文件依赖的文件都被打包进了
main.js
,那些大于 30kb 的第三方包(eg: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.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 服务压力,走本地就好
4. 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;
}
- js 开启 gzip
- 图片是没有 gzip
5. 图片压缩
开发中比较重要的一个环节,图床工具是自带压缩功能的,压缩后直接上传到 CDN 上
如果没有图床工具,该如何压缩图片呢?
- 智图压缩(百度很难搜到官网了,免费、批量、好用)
- tinypng(免费、批量、速度块)
- fireworks工具压缩像素点和尺寸(自己动手,掌握尺度)
- 找 UI 压缩后发给你
图片压缩是常用的手法,因为设备像素点的关系,UI 给予的图片一般都是 x2,x4 的,所以压缩就非常有必要
6. 图片分割
如果页面中有一张效果图(eg:真机渲染图),UI 不让压缩。这时候不妨考虑一下分割图片
- 建议单张图片的大小不要超过 100k,在分割完图片后,通过布局再拼接在一起。可以提高图片加载效率
- 这里注意一点,分割后的每张图片一定要给 height,否则网速慢的情况下样式会塌陷
7. sprite
南方叫精灵图,北方叫雪碧图
- 在网站中有很多小图片时,一定要把这些小图片合并为一张大的图片,然后通过 background 分割到需要展示的图片
浏览器请求资源的时候,同源域名请求资源的时候有最大并发限制,chrome 为 6个
- 页面上有 10 个相同 CDN 域名小图片,那么需要发起 10 次请求去拉取,分两次并发。第一次并发请求回来后,发起第二次并发
- 如果把 10 个小图片合并为一张大图片的画,那么只用一次请求即可拉取下来 10 个小图片的资源。减少服务器压力,减少并发,减少请求次数
8. 懒加载
懒加载(延迟加载),指在长网页中延迟加载图像,是一种非常好的优化网页性能的方式
- 当可视区域没有滚到资源需要加载的地方时候,可视区域外的资源就不会加载
- 可以减少服务器负载,常适用于图片很多,页面较长的业务场景中
如何使用懒加载呢?
9. CDN
1. 概念
CDN(Content Delivery Network,内容分发网络)是指一种通过互联网互相连接的电脑网络系统,利用最靠近每位用户的服务器,更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户,来提供高性能、可扩展性及低成本的网络内容传递给用户
典型的 CDN 系统由三个部分组成:
- 分发服务系统:
- 最基本的工作单元就是 Cache 设备,Cache(边缘 Cache)负责直接响应最终用户的访问请求,把缓存在本地的内容快速地提供给用户。同时 Cache 还负责与源站点进行内容同步,把更新的内容以及本地没有的内容从源站点获取并保存在本地。Cache 设备的数量、规模、总服务能力是衡量一个 CDN 系统服务能力的最基本的指标
- 负载均衡系统:
- 主要功能是负责对所有发起服务请求的用户进行访问调度,确定提供给用户的最终实际访问地址。两级调度体系分为全局负载均衡(GSLB)和本地负载均衡(SLB)
- 全局负载均衡:主要根据用户就近性原则,通过对每个服务节点进行“最优”判断,确定向用户提供服务的 cache 的物理位置
- 本地负载均衡:主要负责节点内部的设备负载均衡
- 运营管理系统:
- 运营管理系统分为运营管理和网络管理子系统,负责处理业务层面的与外界系统交互所必须的收集、整理、交付工作,包含客户管理、产品管理、计费管理、统计分析等功能
2. 作用
CDN 一般用来托管 Web 资源(文本、图片、脚本等),可供下载的资源(媒体文件、软件、文档等),应用程序(门户网站等)。使用 CDN 来加速这些资源的访问
- 在性能方面
- 用户收到的内容来自最近的数据中心,延迟更低,内容加载更快
- 部分资源请求分配给了 CDN,减少了服务器的负载
- 在安全方面,CDN 有助于防御 DDoS、MITM 等网络攻击
- 针对 DDoS:通过监控分析异常流量,限制其请求频率
- 针对 MITM:从源服务器到 CDN 节点到 ISP(Internet Service Provider),全链路 HTTPS 通信
除此之外,CDN 作为一种基础的云服务,同样具有资源托管、按需扩展(能够应对流量高峰)等方面的优势
3. 原理
CDN 和 DNS 有着密不可分的联系
1. DNS解析域名过程
在浏览器输入 www.test.com
- 检查浏览器缓存
- 检查操作系统缓存,常见的如 hosts 文件
- 检查路由器缓存
- 如果前几步都没没找到,会向ISP(网络服务提供商)的LDNS服务器查询
- 如果 LDNS 服务器没找到,会向根域名服务器(Root Server)请求解析,分为以下几步:
- 根服务器返回顶级域名(TLD)服务器(eg:
.com
、.cn
、.org
等)的地址,该例返回.com
的地址 - 接着向顶级域名服务器发送请求,然后会返回次级域名(SLD)服务器的地址,本例返回
.test
的地址 - 接着向次级域名服务器发送请求,然后会返回通过域名查询到的目标 IP,本例返回
www.test.com
的地址 - Local DNS Server 会缓存结果,并返回给用户,缓存在系统中
- 根服务器返回顶级域名(TLD)服务器(eg:
2. CDN的工作原理
- 用户未使用 CDN 缓存资源的过程
- 浏览器通过 DNS 对域名进行解析,依次得到此域名对应的 IP 地址
- 浏览器根据得到的 IP 地址,向域名的服务主机发送数据请求
- 服务器向浏览器返回响应数据
- 用户使用 CDN 缓存资源的过程
- 对于点击的数据的 URL,经过本地 DNS 系统的解析,发现该 URL 对应的是一个 CDN 专用的 DNS 服务器,DNS 系统就会将域名解析权交给 CNAME 指向的 CDN 专用的 DNS 服务器
- CND 专用 DNS 服务器将 CND 的全局负载均衡设备 IP 地址返回给用户
- 用户向 CDN 的全局负载均衡设备发起数据请求
- CDN 的全局负载均衡设备根据用户的 IP 地址,以及用户请求的内容 URL,选择一台用户所属区域的区域负载均衡设备,告诉用户向这台设备发起请求
- 区域负载均衡设备选择一台合适的缓存服务器来提供服务,将该缓存服务器的 IP 地址返回给全局负载均衡设备
- 全局负载均衡设备把服务器的 IP 地址返回给用户
- 用户向该缓存服务器发起请求,缓存服务器响应用户的请求,将用户所需内容发送至用户终端
- 如果缓存服务器没有用户想要的内容,那么缓存服务器就会向它的上一级缓存服务器请求内容,以此类推,直到获取到需要的资源。最后如果还是没有,就会回到自己的服务器去获取资源
CNAME(别名):在域名解析中,实际上解析出来的指定域名对应的 IP 地址,或该域名的一个 CNAME,然后再根据这个 CNAME 来查找对应的 IP 地址
4. 使用场景
- 使用第三方的 CDN 服务:如果想要开源一些项目,可以使用第三方的 CDN 服务
- 使用 CDN 进行静态资源的缓存:将自己网站的静态资源放在 CDN 上(eg:js、css、图片等)。可以将整个项目放在 CDN 上,完成一键部署
- 直播传送:直播本质上是使用流媒体进行传送,CDN 也是支持流媒体传送的,所以直播完全可以使用 CDN 来提高访问速度。CDN 在处理流媒体的时候与处理普通静态文件有所不同,普通文件如果在边缘节点没有找到的话,就会去上一层接着寻找,但是流媒体本身数据量就非常大,如果使用回源的方式,必然会带来性能问题,所以流媒体一般采用的都是主动推送的方式来进行
10. Web Worker
为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行
- 在主线程运行的同时,Worker 线程在后台运行,两者互不干扰
- 等到 Worker 线程完成计算任务,再把结果返回给主线程
- 好处:一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢
11. 缓存
- 原理:
更快读写的存储介质 + 减少 IO + 减少 CPU 计算 = 性能优化
- 性能优化的第一定律:优先考虑使用缓存
缓存主要手段:
- 浏览器缓存
- CDN
- 反向代理
- 本地缓存
- 分布式缓存
- 数据库缓存
12. GPU渲染
每个网页或多或少涉及到一些 CSS 动画,通常简单的动画对于性能的影响微乎其微,然而如果涉及到稍显复杂的动画,不当的处理方式会使性能问题变得十分突出
- 像 Chrome、FireFox、Safari、IE9+、最新版本的 Opera 都支持 GPU 加速,当它们检测到页面中某个 DOM 元素应用了某些 CSS 规则时就会开启
- 虽然我们可能不想对元素应用 3D 变换,可一样可以开启 3D 引擎(eg:可以用
transform: translateZ(0)
来开启 GPU 加速) - 只对需要实现动画效果的元素应用,如果仅仅为了开启硬件加速而随便乱用,是不合理的
13. Ajax可缓存
Ajax 在发送的数据成功后,为了提高页面的响应速度和用户体验,会把请求的URL和返回的响应结果保存在缓存内,当下一次调用Ajax发送相同的请求(URL和参数完全相同)时,它就会直接从缓存中拿数据
- 在进行 Ajax 请求时,可以尽量选择使用 get 请求,这样可以使用客户端缓存,提高请求速度
14. Resource Hints
Resource Hints(资源预加载)是非常好的一种性能优化方法,可以大大降低页面加载时间,给用户更加流畅的用户体验
- 现代浏览器使用大量预测优化技术来预测用户行为和意图,这些技术有预连接、资源与获取、资源预渲染等
Resource Hints 的思路有如下两个:
- 当前将要获取资源的列表
- 通过当前页面或应用的状态、用户历史行为或 session 预测用户行为及必需的资源
实现 Resource Hints 方法:
- 可分为基于 link 标签的
DNS-prefetch, subresource, preload, prefetch, preconnect, prerender
- 本地存储 localStorage
15. SSR
渲染过程在服务器端完成,最终的渲染结果 HTML 页面通过 HTTP 协议发送给客户端,又被认为是 “同构” 或 “通用”,如果项目有大量的 detail 页面,相互特别频繁,建议选择服务端渲染
- 服务端渲染(SSR)除了 SEO 还有很多时候用作首屏优化,加快首屏速度,提高用户体验。但是对服务器有要求,网络传输数据量大,占用部分服务器运算资源
- Vue 的
Nuxt.js
和 React 的next.js
都是服务端渲染的方法