优化 getUserInfo 请求
要求
getUserInfo 是个通用接口,在各个模块里面都有可能使用 requestUserInfo 模拟的是请求服务端真正获取用户信息的方法
业务背景
- 在一个页面有 A, B, C 等多个功能模块,A, B, C 模块渲染执行顺序不可控
- 每个模块都会调用 getUserInfo 这个方法, 这个方法是可以直接调用 requestUserInfo 获取用户信息
- 调用三次就会发起三次网络请求
- 现在需要优化 getUserInfo 这个方法, 保证 getUserInfo 方法3次调用后, 最终只会发出一次网络请求。
测试用例
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。
实现
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)})}})
}