frontend-interview-question-and-answer
frontend-interview-question-and-answer copied to clipboard
[快手]如何对请求进行缓存
如何对请求进行缓存,例如有10个异步请求,如果有一个异步请求返回结果剩下的请求就用这个结果,并且能过传入成功和失败的回调函数
使用强缓存
表示在缓存期间不需要请求
可以通过设置HTTP Header 实现:
- Expires
- Cache-Control
Expires
Expires是HTTP/1中的,表示资源在指定时间之后失效,需要重新请求- 受限制与本地时间,可以通过修改本地时间导致其失效
// 2020-03-10 11:11:28 后失效,需要重新请求
res.setHeader('Expires','Tue Mar 10 2020 11:11:28 GMT+0800')
Cache-Control
- Cache-Control 出现于 HTTP/1.1,优先级高于 Expires
- 可以组合使用多种指令
// 10s后失效
res.setHeader('Cache-control', 'max-age=10')
常见指令
| 指令 | 作用 |
|---|---|
| public | 响应可以被服务端或者客户顿缓存 |
| private | 响应只可以被客户端缓存 |
| max-age=30 | 缓存30s后过期需要重新请求 |
| s-maxage=30 | 覆盖max-age,作用一致,代理服务器才生效 |
| no-store | 不缓存任何响应 |
| no-cache | 资源能被缓存,但立即失效 |
| max-stale=30 | 30s内,即使缓存过期也使用该缓存 |
| min-fresh=30 | 希望30s内获取最新的响应 |
使用示例(以Node为例)
const http = require('http')
let server = http.createServer(async (req, res) => {
// -------跨域支持-----------
// 放行指定域名
res.setHeader('Access-Control-Allow-Origin', '*')
//跨域允许的header类型
res.setHeader("Access-Control-Allow-Headers", "*");
let { method, url } = req
if (method === 'OPTIONS') {
return res.end()
}
console.log(method, url)
if (url === '/api/expires') {
// 设置过期时间
res.setHeader('Expires', 'Tue Mar 10 2020 11:11:28 GMT+0800')
return res.end(`Expires---${new Date()}`)
}
if (url === '/api/cache') {
// 设置10s后过期,需重新请求
res.setHeader('Cache-control', 'max-age=10')
return res.end(`Cache-control---${new Date()}`)
}
res.end('success')
})
// 启动
server.listen(3000, err => {
console.log(`listen 3000 success`);
})
Axios请求示例
<button id="cache">cache</button>
<button id="expires">expires</button>
<script>
expires.addEventListener('click', function () {
for (let i = 0; i < 10; i++) {
axios.get('http://localhost:3000/api/expires')
.then(res => {
let { status, data } = res
console.log(status, data)
})
}
})
cache.addEventListener('click', function () {
for (let i = 0; i < 10; i++) {
axios.get('http://localhost:3000/api/cache')
.then(res => {
let { status, data } = res
console.log(status, data)
})
}
})
</script>
结果
客户端请求
服务端响应一次
简单写下针对GET 请求进行缓存的就可以了吧,其他思路都差不多
function request(url, success, failure) {
const cache = request.cache[url];
let promise = null;
if (!cache) {
console.log('not cache');
promise = fetch(url);
request.cache[url] = promise;
} else {
console.log('cache');
promise = request.cache[url];
}
console.log(promise);
promise
.then(res => {
return res.clone().json()
})
.then(json => {
success(json);
})
.catch(error => {
failure(error);
})
}
request.cache = {};
const promise1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'two');
});
function getRaceApis(promiseArr){
return new Promise(function(resolve, reject) {
try {
Promise.race(promiseArr).then(function(value) {
return Promise.allSettled(promiseArr).
then((results) => results.forEach((result) => console.log(value)));
// Both resolve, but promise2 is faster
})
} catch(err) {
reject(err)
}
});
}
getRaceApis([promise1, promise2]).then((result) => {console.info(result)})
