资源压缩入门:常见压缩算法概览
压缩算法这东西,说白了就是给资源「瘦身」。我在刚接触前端性能优化时,总觉得压缩是件很简单的事——找个工具跑一遍不就完了?后来踩过几次坑才发现,选错算法,有时候比不压缩还难受。
这一章,我带大家把几个主流压缩算法过一遍。不搞复杂的数学公式,咱们就聊它们怎么用、效果如何、坑在哪。
无损压缩 vs 有损压缩:先搞清楚这个
这两个概念是压缩的根基。我见过不少新手把 JS 文件用有损压缩跑了一遍,结果代码直接跑不起来……嗯,血的教训。
| 类型 | 特点 | 适用场景 | 典型算法 |
|---|---|---|---|
| 无损压缩 | 解压后数据与原始数据完全一致,不丢失任何信息 | 代码、文本、配置文件、数据库备份 | Gzip、Brotli、Zstd、Deflate |
| 有损压缩 | 丢弃部分人眼/人耳不敏感的信息,换取更高压缩比 | 图片、音频、视频 | JPEG、WebP(有损模式)、MP3、AAC |
三大主流无损压缩算法
现在前端资源压缩,基本就是 Gzip、Brotli、Zstd 这三家争霸。我按自己的使用经验,一个一个说。
Gzip:老牌劲旅,兼容性之王
Gzip 诞生于 1992 年,到现在快 30 年了。它基于 Deflate 算法,压缩率中规中矩,但胜在所有浏览器和服务端都支持。
我在项目中遇到过一个场景:某客户的内网环境只允许 HTTP/1.1,而且服务器是古董级的 Nginx 1.10。这时候 Brotli 和 Zstd 都上不了,只能用 Gzip。说白了,Gzip 就是那个「不管环境多烂,它都能跑」的保底方案。
Brotli:Google 出品,现代 Web 的首选
Brotli 是 Google 在 2015 年推出的算法。它的压缩率比 Gzip 高 20-30%,而且针对 Web 资源(HTML、CSS、JS)做了专门优化。
我记得有一次优化一个 React 应用,Gzip 压缩后的 vendor.js 是 180KB,换成 Brotli 后直接降到 130KB。用户首屏加载时间从 2.8 秒降到了 2.1 秒。这个提升是实打实的。
不过 Brotli 有个坑:它需要 HTTPS 支持。因为 Brotli 压缩需要更高的 CPU 开销,浏览器只在 HTTPS 连接下才会接受 Brotli 压缩的资源。如果你的站点还是 HTTP,那 Brotli 就用不了。
Zstd:后起之秀,速度与压缩比的平衡大师
Zstd(Zstandard)是 Facebook 在 2016 年开源的算法。它的特点是:压缩速度极快,解压速度更快。在同等压缩率下,Zstd 的压缩速度是 Gzip 的 3-5 倍,解压速度是 Gzip 的 10 倍以上。
我目前在两个场景下会优先用 Zstd:
- 构建产物缓存:CI/CD 流水线中,把构建产物用 Zstd 压缩后上传到对象存储,速度比 Gzip 快很多。
- 服务端资源预压缩:对于需要频繁读取的静态资源,用 Zstd 预压缩后存盘,读取时解压几乎不消耗 CPU。
但 Zstd 在浏览器端的支持还不够好。目前只有 Chrome 和 Firefox 的部分版本原生支持 Zstd 解压,所以不能直接用于 Web 资源传输。它更适合服务端内部的数据交换和存储。
压缩率与速度的权衡
你想想看,压缩算法本质上是在做一件事:用时间换空间。压缩级别越高,文件越小,但压缩耗时越长。这个权衡,在线上环境尤其重要。
我给大家看一组我实际测试的数据(测试文件:一个 2.3MB 的 Vue 应用打包后的 JS 文件):
| 算法 | 压缩级别 | 压缩后大小 | 压缩耗时 | 解压耗时 |
|---|---|---|---|---|
| Gzip | 6 | 680 KB | 1.2 秒 | 0.3 秒 |
| Gzip | 9 | 650 KB | 3.5 秒 | 0.3 秒 |
| Brotli | 4 | 520 KB | 2.1 秒 | 0.2 秒 |
| Brotli | 11 | 480 KB | 8.7 秒 | 0.2 秒 |
| Zstd | 3 | 560 KB | 0.4 秒 | 0.05 秒 |
| Zstd | 19 | 460 KB | 12.3 秒 | 0.05 秒 |
从这张表能看出几个规律:
- Brotli 压缩率最高,但压缩耗时也最长。如果是在构建阶段预压缩,Brotli 级别 4-6 是比较好的平衡点。
- Zstd 解压速度无敌,适合读多写少的场景。我习惯在 CI 缓存中用 Zstd 级别 3,又快又小。
- Gzip 级别 6 是黄金档位,再往上提级别,收益递减明显。
算法选择决策流程
说了这么多,到底该怎么选?我画了一张图,把决策逻辑串起来:
实际项目中的配置示例
光说不练假把式。我给大家看几个实际配置,都是我在生产环境用过的。
Nginx 配置:同时支持 Gzip 和 Brotli
# 开启 Gzip
gzip on;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# 开启 Brotli(需要安装 ngx_brotli 模块)
brotli on;
brotli_comp_level 4;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
这里有个细节:Brotli 的级别 4 对应 Gzip 的级别 6,压缩率更高,速度还差不多。我建议你直接照搬这个配置。
Webpack 构建配置:预压缩静态资源
// webpack.config.js
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
plugins: [
// 生成 .gz 文件
new CompressionPlugin({
algorithm: 'gzip',
test: /\.(js|css|html|svg)$/,
threshold: 10240, // 只压缩大于 10KB 的文件
minRatio: 0.8, // 压缩率低于 0.8 才保留
}),
// 生成 .br 文件
new CompressionPlugin({
algorithm: 'brotliCompress',
test: /\.(js|css|html|svg)$/,
threshold: 10240,
minRatio: 0.8,
}),
],
};
这样构建后,dist 目录下每个资源都有 .gz 和 .br 两个版本。Nginx 会根据请求头中的 Accept-Encoding 自动返回对应的压缩文件。
本章小结
这一章我们聊了三个核心点:
- 无损 vs 有损:代码和文本必须用无损,图片和音视频可以用有损。
- 三大算法:Gzip 兼容性最好,Brotli 压缩率最高,Zstd 速度最快。
- 权衡取舍:不要盲目追求最高压缩级别,要根据场景选合适的算法和级别。