问题由来
通常前后端交互时候,会有一个token,这个token是有有效期和刷新机制的。
一般刷新策略是在每次api请求时候检查token是否将要过期,从而决定是否刷新。
这里就有一个问题了,刚加载一个页面时候,会有好几个api并发进行GET请求,如果token时间恰好达到刷新时间,那么会请求好几遍刷新token的接口,虽然最终存储的是一个token,但是请求好几次,很不优雅。
这种情况就可以使用promise对象来构造扇入扇出代码,从而在并发时候,保证只有一次请求token刷新。
代码复现
//定义token刷新接口
async function refrestoken(index){
//模拟获取token
console.log("GET token_" + index)
//模拟存储token
console.log("save token_" + index)
//返回token
return "token_"+index
};
//并发请求刷新
(async function(){
let token = await refrestoken(1)
console.log(token)
})();
//并发请求刷新
(async function(){
let token = await refrestoken(2)
console.log(token)
})();
//并发请求刷新
(async function(){
let token = await refrestoken(3)
console.log(token)
})()
代码解析:
- promise对象除了用new Promise() 还可以使用async function(){}函数式方式实现
- 该代码模拟了请求刷新token接口,同时并发请求三个token刷新接口。
- 改代码打印结果如下
GET token_1
save token_1
GET token_2
save token_2
GET token_3
save token_3
token_1
token_2
token_3
虽然最后token只存储并使用token_3,系统运行没问题,但是多请求了两次token。
实现请求合并并对token进行扇出
let tokenPromise = null;
async function refrestoken(index){
//模拟获取token
console.log("GET token_" + index)
//模拟存储token
console.log("save token_" + index)
//返回token
return "token_"+index
};
(async function(){
if(tokenPromise == null){
//重点 promise对象也可以重复使用
tokenPromise = refrestoken(1)
let token = await tokenPromise;
console.log(token)
tokenPromise = null;
}else{
let token = await tokenPromise;
console.log(token)
}
})();
(async function(){
if(tokenPromise == null){
tokenPromise = refrestoken(2)
let token = await tokenPromise;
console.log(token)
tokenPromise = null;
}else{
let token = await tokenPromise;
console.log(token)
}
})();
(async function(){
if(tokenPromise == null){
tokenPromise = refrestoken(3)
let token = await tokenPromise;
console.log(token)
tokenPromise = null;
}else{
let token = await tokenPromise;
console.log(token)
}
})()
代码解析:
- 返回结果:
GET token_1
save token_1
token_1
token_1
token_1
通过打印结果可以看出,只调用一次token刷新接口,同时并发的三个请求接口都获取到同一个token结果。
- 重点代码
tokenPromise = refrestoken(1); let token = await tokenPromise;
- promise是对象,重复进行await调用,并且每次时候,会阻塞,直到promise返回结。