挑战:AVIF 编码速度慢
在 Framer,我们在第一次请求时优化每一张图片。优化后的图片随后被缓存到 CDN 上。
这是一种常见的方法,它运行良好,但也有一个缺点。因为第一次未缓存的请求必须转换和调整图片大小,所以它比后续请求花费的时间更长。对于 WebP 来说,“更长”是显而易见的但可以接受的:在我们的基础设施中,WebP 转换通常会增加 100-300 毫秒。然而,对于 AVIF,这会增加到 1-2 秒。
旁注:“1-2 秒?这还不够快吗?”——这很快,但只在计算机上下文之外。“研究表明,用户在仅仅 100 毫秒后就会觉得事情不是即时的。”
Framer 图片的缓存命中率约为 98%。如果我们忽略这个问题并切换到 AVIF,每第 50 张图片将需要几秒钟才能加载。我们认为这是不可接受的,因此 Framer 的Jacob提出,并且Piotr实现了一个巧妙的策略,避免了这种情况——`stale-while-revalidate` 头部。
解决方案:`Stale-While-Revalidate`
stale-while-revalidate是一种缓存设置。它是`Cache-Control`头部中的一个参数,它告诉 CDN 在图片过期后可以继续提供多长时间:
以下是我们如何使用它来确保 AVIF 永远不会使图片响应变慢:
1. 首次请求:WebP
在第一个请求中,我们将图片作为 WebP 提供,而不是 AVIF。
我们还将`Cache-Control`头部设置为`max-age=0, stale-while-revalidate=31536000`
2. 立即过期
由于`max-age`设置为 0,WebP 图片立即过期。这会促使 CDN 将第二个请求转发给我们。
3. 第二次请求:AVIF
当第二个请求到达时,我们将图片作为 AVIF 提供。
响应第二次请求可能需要几秒钟,因为 AVIF 转换很慢。但多亏了`stale-while-revalidate`,我们的 CDN (CloudFront) 会继续提供 WebP 图片,直到转换完成。
我们通过`If-None-Match`头部识别第二次请求与第一次请求。只有第二次请求才有它。
当 AVIF 图片准备好后,我们将其与`Cache-Control: max-age=31536000`一起返回。这允许 CDN 缓存并长期提供它。
这出乎意料地有效——最重要的是,它使我们能够保持基础设施的简单。如果不是这个技巧,我们将需要实现一个单独的队列系统来在后台转换图像。但是有了这个技巧,我们不需要——因此没有额外的复杂性,也没有额外的错误。
我们何时不使用 AVIF
AVIF 现在是大多数图片的默认格式。但仍有一些场景我们继续使用 WebP:
无损图像:AVIF 的无损压缩并非真正的无损,而且比 WebP 的更差。因此,对于无损图像,我们继续使用 WebP。
动画图像:我们用来优化图像的库不支持动画 AVIF 图像,因此我们继续为此类图像使用 WebP。

