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
相关产品推荐
相关产品推荐

