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

TypeScript中如何避免链式Promise使用.then或重复await?

问题

我封装了Playwright的Page类来简化操作,其中需要模拟输入+按Tab键的流程(贴近用户真实行为,用于测试Tab键顺序是否符合预期)。当前的封装类代码如下:

import { Locator, Page } from "@playwright/test";
class SimplePage {
  constructor(private readonly page: Page) {}
  async type(text: string): Promise<this> {
    await this.page.keyboard.type(text);
    return this;
  }
  async tab(): Promise<this> {
    await this.page.keyboard.press("Tab");
    return this;
  }  
}

目前只能用以下两种方式调用:

方式一:

await myPage.type(programName)
  .then((p) => p.tab())
  .then((p) => p.type(shortName))
  .then((p) => p.tab());

方式二:

await myPage.type(programName);
await myPage.tab();
await myPage.type(shortName);
await myPage.tab();

我想实现更简洁的链式调用写法:

await myPage
  .type(programName)
  .tab()
  .type(shortName)
  .tab();
解决方案

之所以无法直接链式调用,是因为type和tab都是异步方法,返回的是Promise<this>而非this本身,所以不能直接在Promise上调用类的方法。要实现你想要的链式写法,可以通过以下两种方式修改封装类:

方法一:用链式队列管理异步操作

在类内部维护一个Promise队列,每个方法不直接执行异步操作,而是把操作加入队列,同时返回类实例本身,最后通过done()方法等待所有操作完成:

import { Locator, Page } from "@playwright/test";
class SimplePage {
  private operationQueue: Promise<this> = Promise.resolve(this);

  constructor(private readonly page: Page) {}

  type(text: string): this {
    this.operationQueue = this.operationQueue.then(async (self) => {
      await self.page.keyboard.type(text);
      return self;
    });
    return this;
  }

  tab(): this {
    this.operationQueue = this.operationQueue.then(async (self) => {
      await self.page.keyboard.press("Tab");
      return self;
    });
    return this;
  }

  // 等待所有链式操作完成
  async done(): Promise<this> {
    return this.operationQueue;
  }
}

调用方式:

await myPage
  .type(programName)
  .tab()
  .type(shortName)
  .tab()
  .done();

方法二:让Promise挂载类的方法

通过给返回的Promise对象挂载类的所有方法,这样就可以在Promise上直接链式调用后续方法,最后用await等待整个链执行完成:

import { Locator, Page } from "@playwright/test";
class SimplePage {
  constructor(private readonly page: Page) {}

  // 给Promise挂载当前类的所有方法
  private wrapPromise(promise: Promise<this>): Promise<this> & SimplePage {
    return Object.assign(promise, this) as Promise<this> & SimplePage;
  }

  async type(text: string): Promise<this> & SimplePage {
    await this.page.keyboard.type(text);
    return this.wrapPromise(Promise.resolve(this));
  }

  async tab(): Promise<this> & SimplePage {
    await this.page.keyboard.press("Tab");
    return this.wrapPromise(Promise.resolve(this));
  }
}

调用方式完全符合你的需求:

await myPage
  .type(programName)
  .tab()
  .type(shortName)
  .tab();

内容的提问来源于stack exchange,提问作者Archimedes Trajano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 14:58:27