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

如何在解析其他Promise前等待连接完成?

异步客户端连接的竞态问题与简洁修复方案

问题场景

当并发调用Api.request()时,原代码会多次触发客户端连接,不符合"仅初始化一次连接,所有请求复用该连接"的预期。

原代码

class Client {
  async connect() {
      return new Promise(resolve => {
          setTimeout(() => {
              console.log('connect');
              resolve()
          }, 2000);
      })
  }

  async request() {
      console.log('request completed')
  }
}

class Api {
  #client;

  async getClient() {
      if (!this.#client) {
          const client = new Client();
          await client.connect();
          this.#client = client;
      }
      return this.#client;
  }

  async request() {
      const client = await this.getClient();
      return client.request();
  }
}

const run = async () => {
  const api = new Api();

  await Promise.all([api.request(), api.request(), api.request(), api.request()]);
}

run();

错误输出

connect
request completed
connect
request completed
connect
request completed
connect
request completed

期望输出

connect
request completed
request completed
request completed
request completed

简洁修复方案

核心思路是用Promise存储连接状态,让所有并发请求等待同一个连接Promise,避免重复初始化。仅需修改Api类的少量代码,几乎不改动原有结构:

class Client {
  async connect() {
      return new Promise(resolve => {
          setTimeout(() => {
              console.log('connect');
              resolve()
          }, 2000);
      })
  }

  async request() {
      console.log('request completed')
  }
}

class Api {
  #clientPromise; // 存储连接Promise,而非直接存储客户端实例

  async getClient() {
      if (!this.#clientPromise) {
          const client = new Client();
          // 将connect的Promise保存,后续请求共享该Promise
          this.#clientPromise = client.connect().then(() => client);
      }
      return this.#clientPromise;
  }

  async request() {
      const client = await this.getClient();
      return client.request();
  }
}

const run = async () => {
  const api = new Api();

  await Promise.all([api.request(), api.request(), api.request(), api.request()]);
}

run();

方案原理

  1. 第一次调用getClient()时,创建Client实例并发起连接,同时将connect()的Promise(最终resolve为client实例)赋值给#clientPromise
  2. 后续并发请求进入getClient()时,#clientPromise已存在,直接await该Promise,所有请求共享同一个连接流程
  3. 连接完成后,所有请求会拿到同一个client实例,实现复用

对比原有解决方案

此方案仅调整了Api类中客户端实例的存储方式,无需额外维护#connecting状态和请求队列,代码更简洁、可读性更强,同时完美解决竞态问题。

内容的提问来源于stack exchange,提问作者Andrew Rusinas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 06:15:32