V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
gromit1337
V2EX  ›  JavaScript

一个面试题

  •  
  •   gromit1337 · 2023-05-31 22:30:51 +08:00 · 1268 次点击
    这是一个创建于 571 天前的主题,其中的信息可能已经有所发展或是发生改变。

    优化 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) => {}
    
    6 条回复    2023-06-02 12:08:31 +08:00
    ChefIsAwesome
        1
    ChefIsAwesome  
       2023-05-31 23:02:08 +08:00 via Android
    可以再加几种变化:
    重试请求。失败的请求插到队列尾重试或者插到下一组重试,重试 n 次之后报错。
    按顺序显示结果。比方说并发的 1 、2 个请求,返回顺序是 2 、1 。要求 2 返回时不处理,1 返回时再依次处理 1 、2 。
    延迟。并发的一组结束之后,等待一段时间再开始下一组。
    gromit1337
        2
    gromit1337  
    OP
       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
        3
    uncat  
       2023-06-01 10:24:24 +08:00   ❤️ 1
    并发控制,基于指数退避的超时重试( GPT4 写的)

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

    http://ix.io/4xdh
    zhy0216
        5
    zhy0216  
       2023-06-02 10:19:47 +08:00
    zhy0216
        6
    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++]();
    }
    });
    };
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5484 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 08:55 · PVG 16:55 · LAX 00:55 · JFK 03:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.