一个面试题

2023-05-31 22:30:51 +08:00
 gromit1337

优化 requestUserProfile 并发请求

requestUserProfile 是个通用查询用户信息接口,通过传入 uid ,拿用户昵称 在一个支付宝群聊里有 10 多个用户,点击群聊信息,展示各个人的昵称 10 个并发请求,会阻塞接口 10 个依次请求,耗时久,显示昵称太慢 需要优化请求,在并发和耗时之间掌握一个平衡

// 核心用户请求
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, max = 2) => {}
1150 次点击
所在节点    JavaScript
6 条回复
ChefIsAwesome
2023-05-31 23:02:08 +08:00
可以再加几种变化:
重试请求。失败的请求插到队列尾重试或者插到下一组重试,重试 n 次之后报错。
按顺序显示结果。比方说并发的 1 、2 个请求,返回顺序是 2 、1 。要求 2 返回时不处理,1 返回时再依次处理 1 、2 。
延迟。并发的一组结束之后,等待一段时间再开始下一组。
gromit1337
2023-05-31 23:12:45 +08:00
@ChefIsAwesome 有测试用例的
```javascript
export default async () => {
try {
const star = Date.now();
const result = await Promise.all([
requestUserProfile("1"),
requestUserProfile("2"),
requestUserProfile("3"),
requestUserProfile("1"),
]);

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;
}
};
```
uncat
2023-06-01 10:24:24 +08:00
并发控制,基于指数退避的超时重试( GPT4 写的)

http://ix.io/4xdf
uncat
2023-06-01 10:48:33 +08:00
并发控制,基于指数退避的超时重试,确保请求 url 和 结果的顺序一致,如果超时或错误,则返回空值

http://ix.io/4xdh
zhy0216
2023-06-02 10:19:47 +08:00
zhy0216
2023-06-02 12:08:31 +08:00
```ts
/**
*
* @param uid uid
* @param max 最多并发请求数量
*/
const queue: (() => unknown)[] = [];
let activeCount = 0;
let queueCursor = 0;
const requestUserProfile = (uid: string, max = 2) => {
return new Promise((resolve) => {
const runF = async () => {
activeCount++;
const r = await requestProfile(uid);
activeCount--;
if (queueCursor < queue.length) {
queue[queueCursor++]();
}

return resolve(r);
};

queue.push(runF);

if (activeCount < max) {
queue[queueCursor++]();
}
});
};
```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/944693

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX