05-性能优化

1. tree shaking

中文(摇树),webpack 构建优化中重要一环。摇树用于清除项目中的一些无用代码,它依赖于ES中的模块语法

// 引用 lodash 库,在构建包时是会把整个 lodash 包打入到 bundle 包中的
import _ from 'lodash'

// 引用lodash库,在构建包时只会把 isEmpty 这个方法抽离出来再打入到 bundle 包中
import _isEmpty from 'lodash/isEmpty';

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
        },
    }
})

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;
}
image-20240915205006743
  • js 开启 gzip
image-20240915204841306
  • 图片是没有 gzip
image-20240915204906877

5. 图片压缩

开发中比较重要的一个环节,图床工具是自带压缩功能的,压缩后直接上传到 CDN 上

如果没有图床工具,该如何压缩图片呢?

  • 智图压缩(百度很难搜到官网了,免费、批量、好用)
  • tinypngopen in new window(免费、批量、速度块)
  • 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 系统由三个部分组成:

  1. 分发服务系统:
    • 最基本的工作单元就是 Cache 设备,Cache(边缘 Cache)负责直接响应最终用户的访问请求,把缓存在本地的内容快速地提供给用户。同时 Cache 还负责与源站点进行内容同步,把更新的内容以及本地没有的内容从源站点获取并保存在本地。Cache 设备的数量、规模、总服务能力是衡量一个 CDN 系统服务能力的最基本的指标
  2. 负载均衡系统:
    • 主要功能是负责对所有发起服务请求的用户进行访问调度,确定提供给用户的最终实际访问地址。两级调度体系分为全局负载均衡(GSLB)和本地负载均衡(SLB)
    • 全局负载均衡:主要根据用户就近性原则,通过对每个服务节点进行“最优”判断,确定向用户提供服务的 cache 的物理位置
    • 本地负载均衡:主要负责节点内部的设备负载均衡
  3. 运营管理系统:
    • 运营管理系统分为运营管理和网络管理子系统,负责处理业务层面的与外界系统交互所必须的收集、整理、交付工作,包含客户管理、产品管理、计费管理、统计分析等功能

2. 作用

CDN 一般用来托管 Web 资源(文本、图片、脚本等),可供下载的资源(媒体文件、软件、文档等),应用程序(门户网站等)。使用 CDN 来加速这些资源的访问

  1. 在性能方面
    • 用户收到的内容来自最近的数据中心,延迟更低,内容加载更快
    • 部分资源请求分配给了 CDN,减少了服务器的负载
  2. 在安全方面,CDN 有助于防御 DDoS、MITM 等网络攻击
    • 针对 DDoS:通过监控分析异常流量,限制其请求频率
    • 针对 MITM:从源服务器到 CDN 节点到 ISP(Internet Service Provider),全链路 HTTPS 通信

除此之外,CDN 作为一种基础的云服务,同样具有资源托管、按需扩展(能够应对流量高峰)等方面的优势

3. 原理

CDN 和 DNS 有着密不可分的联系

1. DNS解析域名过程

在浏览器输入 www.test.com

  1. 检查浏览器缓存
  2. 检查操作系统缓存,常见的如 hosts 文件
  3. 检查路由器缓存
  4. 如果前几步都没没找到,会向ISP(网络服务提供商)的LDNS服务器查询
  5. 如果 LDNS 服务器没找到,会向根域名服务器(Root Server)请求解析,分为以下几步:
    • 根服务器返回顶级域名(TLD)服务器(eg:.com.cn.org 等)的地址,该例返回 .com 的地址
    • 接着向顶级域名服务器发送请求,然后会返回次级域名(SLD)服务器的地址,本例返回 .test 的地址
    • 接着向次级域名服务器发送请求,然后会返回通过域名查询到的目标 IP,本例返回 www.test.com 的地址
    • Local DNS Server 会缓存结果,并返回给用户,缓存在系统中

2. CDN的工作原理

  1. 用户未使用 CDN 缓存资源的过程
    1. 浏览器通过 DNS 对域名进行解析,依次得到此域名对应的 IP 地址
    2. 浏览器根据得到的 IP 地址,向域名的服务主机发送数据请求
    3. 服务器向浏览器返回响应数据
  2. 用户使用 CDN 缓存资源的过程
    1. 对于点击的数据的 URL,经过本地 DNS 系统的解析,发现该 URL 对应的是一个 CDN 专用的 DNS 服务器,DNS 系统就会将域名解析权交给 CNAME 指向的 CDN 专用的 DNS 服务器
    2. CND 专用 DNS 服务器将 CND 的全局负载均衡设备 IP 地址返回给用户
    3. 用户向 CDN 的全局负载均衡设备发起数据请求
    4. CDN 的全局负载均衡设备根据用户的 IP 地址,以及用户请求的内容 URL,选择一台用户所属区域的区域负载均衡设备,告诉用户向这台设备发起请求
    5. 区域负载均衡设备选择一台合适的缓存服务器来提供服务,将该缓存服务器的 IP 地址返回给全局负载均衡设备
    6. 全局负载均衡设备把服务器的 IP 地址返回给用户
    7. 用户向该缓存服务器发起请求,缓存服务器响应用户的请求,将用户所需内容发送至用户终端
      • 如果缓存服务器没有用户想要的内容,那么缓存服务器就会向它的上一级缓存服务器请求内容,以此类推,直到获取到需要的资源。最后如果还是没有,就会回到自己的服务器去获取资源
4fa6bb73c1db4bb4bbe72a32fa682289

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 交互)就会很流畅,不会被阻塞或拖慢

Web Worker 使用教程open in new window

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 都是服务端渲染的方法