优化 getUserInfo 请求
要求
getUserInfo 是个通用接口,在各个模块里面都有可能使用 requestUserInfo 模拟的是请求服务端真正获取用户信息的方法
业务背景
- 在一个页面有 A, B, C 等多个功能模块,A, B, C 模块渲染执行顺序不可控
- 每个模块都会调用 getUserInfo 这个方法, 这个方法是可以直接调用 requestUserInfo 获取用户信息
- 调用三次就会发起三次网络请求
- 现在需要优化 getUserInfo 这个方法, 保证 getUserInfo 方法3次调用后, 最终只会发出一次网络请求。
测试用例
ts
import { isEqual } from 'lodash-es';
/**
* 第二题
*/
// 核心用户请求
let _requestTime = 0;
const requestUserInfo = () => {
// 这个方法的实现不能修改
return Promise.resolve().then(() => {
return new Promise<void>((resolve) => {
setTimeout(() => {
// 模拟 ajax 异步,1s 返回
resolve();
}, 1000);
}).then(() => {
_requestTime++;
return {
nick: "nick",
age: "18",
};
});
});
};
async () => {
try {
// 模拟请求
const result = await Promise.all([
getUserInfo(),
new Promise(resolve => setTimeout(async () => { resolve(await getUserInfo()) }, 300)),
new Promise(resolve => setTimeout(async () => { resolve(await getUserInfo()) }, 2300))]);
if (
!isEqual(result, [{
nick: "nick",
age: "18",
}, {
nick: "nick",
age: "18",
}, {
nick: "nick",
age: "18",
}])
) {
throw new Error('Wrong answer');
}
return _requestTime === 1;
} catch (err) {
console.warn('测试运行失败');
console.error(err);
return false;
}
};
思路
- 由于测试用例使用Promise.all调用,则需要返回Promise。
- 又因为只需要调用一次接口则拿到数据之后需要缓存方便共享。
- 一旦有数据那就直接resolve。
- 由于Promise返回的也是Promise,可以缓存第一次的Promise,如果存在则只需要等第一次结束
- 结束之后的Promise我们再通过拿到结果进行resolve。
实现
js
let cache = null;
let preRequest = null;
const getUserInfo = () => {
return new Promise((resolve,reject)=>{
if(cache) resolve(cache)
if(preRequest){
preRequest.then(res=>{
resolve(cache)
}).catch(err=>{
reject(cache)
})
}else{
preRequest = requestUserInfo().then(res => {
cache = res;
resolve(res)
}).catch((err) => {
reject(err)
})
}
})
}