一个前端面试官的思考:当Promise遇上真实业务场景

前言

作为一名前端面试官,我经常遇到这样的候选人:聊 Promise API 的时候说的很溜,我感觉我都没他这么溜,然后再问实际的 Promise 业务场景的时候就不会说了。今天我想分享一个常见的面试题:如何实现并发控制?

面试现场

"你对Promise熟悉吗?" "当然!Promise.all、Promise.race、Promise.any..." "好的,那我们来看一个实际场景..."

场景:批量上传文件

"假设用户要上传100张图片,但是服务器限制同时最多只能处理5个请求,你会怎么处理?"

很多候选人开始慌了:

  • "用Promise.all?"
  • "for循环发请求?"
  • "递归调用?"

问题的本质

其实这类问题的核心是:并发控制。

不是考察对Promise API的记忆,而是考察:

  1. 对异步任务的理解
  2. 对并发控制的认知
  3. 对实际业务场景的处理能力

怎么解决

让我们实现一个通用的并发控制队列:

ts 复制代码
export class TaskQueue {
  private queue: (() => Promise<any>)[] = [];
  private activeCount = 0;
  private maxConcurrent: number;

  constructor(maxConcurrent: number) {
    this.maxConcurrent = maxConcurrent;
  }

  public get pending(): number {
    return this.queue.length;
  }

  public get active(): number {
    return this.activeCount;
  }

  public clear(): void {
    this.queue = [];
  }

  private next() {
    if (this.queue.length === 0 || this.activeCount >= this.maxConcurrent) {
      return;
    }
    const task = this.queue.shift();
    if (task) {
      this.activeCount++;
      task().finally(() => {
        this.activeCount--;
        this.next();
      });
    }
  }

  public add<T>(fn: () => Promise<T>): Promise<T> {
    return new Promise<T>((resolve, reject) => {
      const task = async () => {
        try {
          resolve(await fn());
        } catch (error) {
          reject(error);
        }
      };
      this.queue.push(task);
      this.next();
    });
  }
}

代码解析

  • 类的属性
    • queue : 存储待执行的任务队列
    • activeCount : 当前正在执行的任务数量
    • maxConcurrent : 最大并发数
  • 核心方法
    • add : 添加新任务到队列
    • next : 执行下一个任务
    • clear : 清空任务队列
    • pending : 获取待执行任务数量
    • active : 获取当前执行中的任务数量

示例

ts 复制代码
// 创建队列实例,最大并发数为2
const queue = new TaskQueue(2);

// 模拟异步任务
const createTask = (id: number) => {
  return () => new Promise<string>((resolve) => {
    const duration = Math.random() * 2000;
    setTimeout(() => {
      console.log(`Task ${id} completed`);
      resolve(`Task ${id} result`);
    }, duration);
  });
};

// 添加任务
async function runTasks() {
  console.log('开始执行任务');
  
  // 添加5个任务
  for (let i = 1; i <= 5; i++) {
    queue.add(createTask(i))
      .then(result => console.log(result));
    
    console.log(`Task ${i} added, pending: ${queue.pending}, active: ${queue.active}`);
  }
}

runTasks();

总结

通过这个例子,我们可以看到: 知道API的使用,并不意味着你就会用。但更重要的是理解它能解决什么实际问题

希望这篇文章对你有帮助!如果你有任何问题或建议,欢迎在评论区讨论。

相关推荐
frjc10 分钟前
Node.js 与 npm 极简安装教程
前端·npm·node.js
IMPYLH11 分钟前
HTML 的 <main> 元素
前端·html
深念Y13 分钟前
微服务抽取路线图:从胖单体到 ARM 集群
前端·arm开发·数据库·后端·微服务·云原生·架构
雪芽蓝域zzs30 分钟前
Vue3 + Vite本地模拟数据(读取 JSON 数据)
前端
亿元程序员32 分钟前
还有高手?用Shader让图片中的3D圆环转起来!
前端
LccKyI33 分钟前
C#基础编程 面试题汇总(二)
java·面试·c#
灯澜忆梦34 分钟前
【基于GO的Web开发14】gin请求重定向
前端·后端·golang·gin
qq_4523962335 分钟前
第十一篇:《前端性能优化体系:从加载到交互的全链路》
前端·性能优化·交互
Mh38 分钟前
听说我兄弟喜欢跑车,所以必须安排上
前端·javascript·vue.js
zttbee39 分钟前
vue学习(白话功能版)
前端·vue.js·学习·前端框架