优化 requestUserProfile
并发请求
requestUserProfile
是个通用用户信息接口,通过传入uid,拿用户昵称
在一个群聊里有10多个用户,点击群聊信息,展示各个人的昵称
10个并发请求,会阻塞接口
10个依次请求,耗时久,显示昵称太慢
需要优化请求,在并发和耗时之间掌握一个平衡
import { isEqual } from 'lodash-es';
// 核心用户请求
let _requestTime = 0;
const requestProfile = (uid: string) => {
// 这个方法的实现不能修改
return Promise.resolve().then(() => {
return new Promise<void>((resolve) => {
setTimeout(() => {
// 模拟 ajax 异步,1s 返回
resolve();
}, 1000);
}).then(() => {
_requestTime++;
return {
uid,
nick: `nick-${uid}`,
age: '18',
};
});
});
};
/**
* @param uid uid
* @param max 最多并发请求数量
*/
const requestUserProfile = (uid = '1', max = 2) => {
// 这里调用requestProfile 进行优化
};
/**
* 以下为测试用例,无需修改
*/
export default async () => {
try {
const star = Date.now();
await Promise.all([
requestUserProfile('1'),
requestUserProfile('2'),
requestUserProfile('3'),
requestUserProfile('1'),
]).then((result) => {
if (Date.now() - star < 2000 || Date.now() - star >= 3000) {
throw new Error('Wrong answer');
}
if (
!isEqual(result, [
{
uid: '1',
nick: 'nick-1',
age: '18',
},
{
uid: '2',
nick: 'nick-2',
age: '18',
},
{
uid: '3',
nick: 'nick-3',
age: '18',
},
{
uid: '1',
nick: 'nick-1',
age: '18',
},
])
) {
throw new Error('Wrong answer');
}
});
return _requestTime === 3;
} catch (err) {
console.warn('测试运行失败');
console.error(err);
return false;
}
};
参考答案1
let count = 0;
const memo = {};
/**
* @param uid uid
* @param max 最多并发请求数量
*/
const requestUserProfile = async (uid = '1', max = 2) => {
// 这里调用requestProfile 进行优化
let timer;
const loopRequestProfile = (resolve: any) => {
timer && cancelAnimationFrame(timer);
if (memo[uid]) {
return resolve(memo[uid])
}
if (max > count) {
count += 1;
requestProfile(uid).then((data) => {
count -= 1;
memo[uid] = data;
resolve(data);
});
} else {
// 循坏调用 loopRequestProfile 直到 count < max
timer = requestAnimationFrame(() => {
loopRequestProfile(resolve);
});
}
};
return new Promise(loopRequestProfile);
}
✅ 参考答案2
let count = 0;
const taskQueue = [];
/**
* @param uid uid
* @param max 最多并发请求数量
*/
const requestUserProfile = (uid = '1', max = 2) => {
const pullTask = () => {
if (taskQueue.length === 0) {
return;
}
if (count >= max) {
return;
}
count++;
const { resolve, uid } = taskQueue.shift();
resolve(runTask(uid));
};
const runTask = (id) => {
const promise = requestProfile(id);
promise.then(() => {
count--;
pullTask();
});
return promise;
};
return new Promise((resolve) => {
taskQueue.push({ resolve, uid });
if (count < max) {
count++;
const { resolve, uid } = taskQueue.shift();
resolve(runTask(uid));
}
})
};