背景
在JS 代码的执行过程中,同一事件循环中可能存在多个同样的请求,这些请求得到的都是同样的结果。 通常我们可以通过锁 的机制来限制多个事件循环中的查询,但在同一个循环里,这些请求在没有得到返回结果之前,我们是没法加锁的,因为请求可能会失败。
如果请求量很大,那么就可能导致查询量过大,造成第三方(端、后台)承受一定的压力,影响性能。 这种情况类似于"缓存雪崩" 缓存雪崩是指在某一个时间段内,Cache缓存集中过期失效,如果这个时间段内有大量请求,那么所有的请求都会打到db数据库,导致数据库的访问量暴增,引起数据库崩溃
解决方案
这种情况的处理方法也很简单,需要用到缓存队列 ,在没有获取到查询结果前,我们将所有的请求回调函数都放进缓存队列 里,当唯一的请求得到结果后,再取出所有的回调函数进行执行,类似于Promise
的then
机制。
注意⚠️:这种方案仅适用于所查询的数据为静态数据,在短时间内多次查询的结果均相同的情况
ts
let res // 响应结果
let lock = false // 请求锁
const queue = [] // 请求队列
const doReq = () => { // 请求方法
console.log('正在请求...')
return new Promise(resolve => {
setTimeout(() => resolve(Math.random()), Math.random() * 3000) // 3s内响应
})
}
// 请求缓存
function request(callback) {
if (!res && !lock) {
lock = true
doReq().then((data) => {
res = data
let cb
while(cb = queue.shift()) {
cb(res)
}
lock = false
})
}
if (res) {
callback(res)
} else {
queue.push(callback)
}
}
测试代码 & 打印结果
ts
request(() => { console.log('查询1:', res) })
request(() => { console.log('查询2:', res) })
request(() => { console.log('查询3:', res) })
应用场景
- 调端bridge获取用户信息
- 调后台接口获取静态常量数据
- 等待iframe加载完成执行回调(Vant 主窗口与模拟器的路由同步处理)
- ...