这是 Beta 探索课程,内容结构、实验步骤和示例可能会继续调整。
压缩优化
一张 8.7MB 的照片
我记得第一次意识到图片压缩重要性的场景:用户上传了一张 8.7MB 的手机照片,原图直接展示,首屏加载花了 6 秒。
后来我把这张图压缩到 45KB(WebP 格式,质量 80),肉眼几乎看不出区别,加载时间降到了 200ms。体积下降 99.5%,这就是图片压缩的威力。
图片压缩不是在上线前随手调一个质量参数,而是图片系统的核心收益点:它直接影响首屏速度、CDN 带宽、移动端流量、缓存命中率和用户留存。
异步处理链路
上传链路只保证原图安全落盘,压缩链路通过消息队列异步消费:
用户上传 → 对象存储(原图) → 发布上传事件
↓
压缩服务消费消息
↓
生成多格式、多尺寸派生图
↓
写回元数据表 + 通知 CDN 预热
这样设计的好处是:
- 用户上传不需要等待压缩完成,上传即返回
- 压缩失败不影响原图存储,可以重试
- 可以根据图片类型和业务场景选择不同的压缩策略
格式选择
不同格式适合不同场景,不能一刀切:
| 格式 | 适合场景 | 优势 | 劣势 |
|---|---|---|---|
| JPEG | 照片、复杂色彩 | 兼容性好、体积小 | 不支持透明、有损 |
| PNG | 截图、图标、透明图 | 无损、支持透明 | 体积大 |
| WebP | 大多数场景 | 有损/无损、支持透明、体积比 JPEG 小 25-35% | 老浏览器不支持 |
| AVIF | 高质量照片 | 体积比 WebP 再小 20% | 编码慢、兼容性稍差 |
| GIF | 简单动画 | 兼容性好 | 体积大、仅 256 色 |
我的策略是:服务端同时生成 WebP 和 AVIF,CDN 根据客户端 Accept 头自动返回最优格式。老浏览器退回 JPEG/PNG。
场景化参数
头像、商品图、长图、动图不能套用同一套参数:
const compressStrategies = {
avatar: {
formats: ['webp', 'avif'],
sizes: [48, 96, 160, 320],
quality: 80,
// 头像用圆形裁剪,中心对齐
crop: { type: 'circle', focus: 'center' }
},
product: {
formats: ['webp', 'avif', 'jpeg'],
sizes: [200, 400, 800, 1200],
quality: 85,
// 商品图保留白底,不裁剪
crop: { type: 'contain', background: 'white' }
},
content: {
formats: ['webp', 'avif'],
sizes: ['original', 800, 1200],
quality: 82,
// 内容图按比例缩放,不裁剪
crop: { type: 'scale', fit: 'inside' }
}
};
处理任务模型
压缩服务必须记录每次处理的元数据,方便回溯和优化:
处理记录 = {
原图ID, 原始尺寸, 原始格式, 原始体积,
目标格式, 目标尺寸, 质量因子,
输出体积, 压缩率, 处理耗时,
处理状态, 失败原因, 处理时间, 处理节点
}
有了这些数据,就能回答:
- 哪种格式压缩率最高?
- 哪个尺寸的派生图访问量最大?
- 处理延迟的 P99 是多少?
- 失败率最高的是哪种图片?
降级策略
当压缩失败、格式不被客户端支持、或输出质量低于阈值时,系统要能降级,而不是让图片请求直接失败:
- 压缩失败 → 标记派生图不可用,CDN 回源时返回原图
- 客户端不支持 WebP → CDN 根据 Accept 头自动返回 JPEG
- 输出质量低于阈值 → 自动提高质量参数重新处理
- 处理服务过载 → 暂停非热门尺寸的生成,优先保证热门尺寸
验收标准
完成本章后,你应当能够回答三个工程问题:
- 如何为不同业务场景选择压缩策略? —— 根据图片类型、使用场景、终端设备选择格式、尺寸和质量
- 如何设计可扩展的图片处理任务模型? —— 异步消费、可重试、可观测、可降级
- 如何判断压缩系统是否真的有效? —— 体积下降率、清晰度抽检、处理延迟 P99、失败率
学习时可以把压缩链路当成一个独立子系统来验收:输入必须可追溯,输出必须可复用,策略必须可配置,异常必须可恢复。
