You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript的TableManager类joinTable方法是否存在竞态条件?

问题解答

你的担忧完全成立,确实存在竞态条件

  • 问题出在createTable的异步逻辑上:第一次调用joinTable时,getTable同步执行未找到对应桌子,触发createTable,代码执行到await fetchTable(tableId)时会让出线程等待IO返回
  • 此时如果第二个同ID的joinTable请求进来,第一次的createTable还没执行到this.Tables.push(Table)的步骤,内存里还没有该桌子实例,所以第二个请求的getTable同样返回空,也会触发一次新的createTable调用
  • 最终两次fetchTable执行完成后,会往Tables数组里推入两个同ID的不同实例,完全符合你担心的情况

仅在createTable的push操作前加ID校验不能彻底解决问题

  • 这种方式只能避免内存里最终出现重复的Table实例,但是还是会发起两次完全没必要的fetchTable异步请求
  • 如果你的fetchTable逻辑本身包含建表、写数据库等副作用操作,还会导致数据库层面出现重复写入、主键冲突等问题,并没有从根源解决竞态

推荐解决方案

你可以给TableManager加一个pending状态的映射表,记录正在创建过程中的桌子ID对应的Promise,避免重复触发创建逻辑:

class TableManager {
      /** 存储已创建完成的Table对象数组 **/
      protected Tables = [];
      /** 记录正在创建中的桌子ID对应的Promise **/
      protected pendingCreations = new Map();

      protected getTable(tableId) {
         return this.Tables.find(t => t.id === tableId) ?? null;
      }

      protected async createTable(tableId) {
        // 先判断有没有正在创建的同ID请求,有就直接返回该Promise
        if (this.pendingCreations.has(tableId)) {
          return this.pendingCreations.get(tableId);
        }
        const createPromise = (async () => {
          try {
            const Table = await fetchTable(tableId);
            // 额外加一次校验兜底防止极端情况
            const existTable = this.getTable(tableId);
            if (existTable) return existTable;
            this.Tables.push(Table);
            return Table;
          } finally {
            // 无论创建成功失败都要清除pending状态
            this.pendingCreations.delete(tableId);
          }
        })();
        this.pendingCreations.set(tableId, createPromise);
        return createPromise;
      }

      protected async joinTable(user, tableId) {
          const Table = this.getTable(tableId) ?? await this.createTable(tableId);
          Table.addUser(user);
      }
}

内容的提问来源于stack exchange,提问作者Adam Baranyai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 16:06:03