Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promise.all 调用接口并发请求控制 #15

Open
yijinc opened this issue Jun 28, 2022 · 2 comments
Open

Promise.all 调用接口并发请求控制 #15

yijinc opened this issue Jun 28, 2022 · 2 comments
Labels
coding test or practice

Comments

@yijinc
Copy link
Owner

yijinc commented Jun 28, 2022

目标

优化 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;
  }
};
@yijinc yijinc added the coding test or practice label Jun 28, 2022
@yijinc
Copy link
Owner Author

yijinc commented Jun 28, 2022

解决方法 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);
}

@yijinc yijinc changed the title Coding:调用接口并发请求控制(蚂蚁面试题) Coding:调用接口并发请求控制 Jun 28, 2022
@yijinc yijinc changed the title Coding:调用接口并发请求控制 Promise.all 调用接口并发请求控制 Jun 30, 2022
@yijinc
Copy link
Owner Author

yijinc commented Aug 6, 2022

✅ 解决方法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));
    }
  });
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
coding test or practice
Projects
None yet
Development

No branches or pull requests

1 participant