一个前端面试官的思考:当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的使用,并不意味着你就会用。但更重要的是理解它能解决什么实际问题

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

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
晨米酱3 天前
AGENTS.md:Agent 的上下文策略层
面试·架构·agent
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
彧azz3 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大3 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端