最近看到一个概念叫swr
(stale-while-revalidate),但是我看了好久的文档都没有搞懂,直到自己实操才终于理解。接下来,就分享一下什么是SWR
。
具体概念
首先,官方介绍在这里:www.rfc-editor.org/rfc/rfc5861…
The stale-while-revalidate HTTP Cache-Control extension allows a cache to immediately return a stale response while it revalidates it in the background, thereby hiding latency (both in the network and on the server) from clients.
我按自己的理解翻译一下:
stale-while-revalidate
是HTTP的响应头cache-control
的一个属性值,它允许立马返回一个已经过时(stale)的响应。与此同时浏览器又在背后默默重新发起一次请求,响应的结果被存储起来下次使用。因此它很好的隐藏了服务器或者网络的响应延时。
为什么这里说允许返回一个stale的响应呢?如何判断响应是stale的呢,这是因为stale-while-revalidate
是和max-age
一起使用的,如果时间超过了max-age,则是作为stale。
Cache-Control: max-age=600, stale-while-revalidate=30
-
表示请求的结果在600s内都是新鲜(stale的反义词)的,如果在600s内发起了相同请求,则直接返回磁盘缓存。
-
如果在600s~630s内发起了相同的请求,则响应虽然已经过时(stale)了,但是浏览器会直接把之前的缓存结果返回,与此同时浏览器又在背后自己发一个请求,响应结果留作下次使用。
-
如果超过630s后,发起了相同请求,则这就是一个普通请求,就和第一次请求一样,从服务器获取响应结果,并且浏览器并把响应结果缓存起来。
实际操作
接下来,用express作为后端示例一下:
import express from "express";
const app = express();
app.set("etag", false);
app.use(express.static("public"));
let counts = 1;
app.get("/api/counts", (req,res) => {
console.log("request counts:", counts);
// 设置Cache-Control
res.append("Cache-Control", "max-age=5, stale-while-revalidate=10");
// 手动模拟服务器响应或者网络很慢
setTimeout(() => {
res.json({ counts });
console.log("response counts", counts);
counts = counts + 1;
}, 2000);
});
app.listen(3000, () => {
console.log("running at http://localhost:3000");
});
然后public文件夹放了如下index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
details {
margin-top: 1em;
}
script.visible {
border: 1px solid #009688;
display: block;
font-family: monospace;
margin-top: 1em;
padding: 0.2em;
overflow-x: auto;
white-space: pre;
}
#counts {
background-color: yellow;
}
</style>
</head>
<body>
<h1>Stale-while-revalidate Demo</h1>
<p id="counts"></p>
<button id="refresh">Refresh Request Count</button>
<details>
<summary>View JavaScript</summary>
<script class="visible">
const countsEl = document.getElementById("counts");
const refreshEl = document.getElementById("refresh");
async function updateCounts() {
const response = await fetch("/api/counts");
const responseBody = await response.json();
countsEl.textContent = responseBody.counts;
}
updateCounts();
refreshEl.addEventListener("click", updateCounts);
</script>
</details>
</body>
</html>
具体就是点击按钮发起一次请求,然后获取数据。
这里我们设置的是max-age=5, stale-while-revalidate=10
。
所以如果我们在5s发起第二次请求,就浏览器就会让我们直接用缓存数据,服务器都不会收到这次请求,可以看到左侧服务器打印的还是1!
如果在5s~15s内发起第二次请求:该解释的我都放在下图了。
总结
stale-while-revalidate
, 我觉得还是很难理解的,需要自己写个简单的api试一试。
- 明白什么时候stale-while-revalidate生效:在
max-age
~max-age+stale-while-revalidate
之间生效。# 在600s~630s之间,浏览器会进行stale-while-revalidate Cache-Control: max-age=600, stale-while-revalidate=30
- 什么是stale-while-revalidate:浏览器返回一个已经过时的响应缓存,与此同时浏览器又在背后向服务器发起一次请求,并缓存响应结果。
参考文档: