Как избежать .then или повторного ожидания при объединении обещаний в TypeScript?

Я написал код для переноса Playwright Page, чтобы упростить несколько операций. В одной из моих операций я хотел сделать что-то вроде набора текста и табуляции (это лучше имитирует поведение пользователя, даже если для Playwright оно медленнее, поэтому в первую очередь это проверка того, что порядок табуляции работает должным образом).

Класс для переноса будет примерно таким:

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();

Да, это возможно, но методы должны будут вернуться SimplePage & Promise и правильно управлять цепочкой внутри.

jonrsharpe 22.07.2024 09:30

Есть github.com/hdorgeval/playwright-fluent, но на самом деле я бы не стал использовать этот слишком умный трюк — код непонятен обычным людям, его сложно отлаживать и поддерживать. Просто используйте ванильный синтаксис Playwright, чтобы он был читаемым и неудивительным.

ggorlen 22.07.2024 18:09

Честно говоря, мне нужна только клавиатура, а не все это, как вы сказали, было непонятно

Archimedes Trajano 23.07.2024 13:48
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
1
3
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете присвоить своему классу SimplePage свойство promise и при каждом вызове tab или text заменять это обещание новым связанным обещанием.

Наконец, сделайте SimplePage thenable, определив метод then. Таким образом, он будет реагировать на оператор await, как и ожидалось:

class SimplePage {
  private promise: Promise<void> = Promise.resolve();

  constructor(private readonly page: Page) {}

  type(text: string): SimplePage {
    this.promise = this.promise.then(() => this.page.keyboard.type(text));
    return this;
  }

  tab(): SimplePage {
    this.promise = this.promise.then(() => this.page.keyboard.press("Tab"));
    return this;
  }

  then(onFulfill: (value: any) => void, onReject: (error: any) => void) {
    return this.promise.then(onFulfill, onReject);
  }
}

Реализация PromiseLike:

Объявление типа для then будет таким:

class SimplePage implements PromiseLike<void> {
  private promise: Promise<void> = Promise.resolve();

  constructor(private readonly page: Page) {}

  type(text: string): SimplePage {
    this.promise = this.promise.then(() => this.page.keyboard.type(text));
    return this;
  }

  tab(): SimplePage {
    this.promise = this.promise.then(() => this.page.keyboard.press("Tab"));
    return this;
  }

  then<TResult1, TResult2>(
      onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null | undefined, 
      onrejected?:  ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined
      ): PromiseLike<TResult1|TResult2> {
    return this.promise.then(onfulfilled, onrejected);
  }
}

Можете ли вы привести пример кода, который это использует?

Archimedes Trajano 22.07.2024 12:59

Код, который вы указали в вопросе, должен работать с этим. См. уменьшенный пример на сайте replit.com, где я использовал макетную реализацию Page.

trincot 22.07.2024 13:20

Потребовалось немного времени, чтобы понять, как это работает, но интересно насчет then в конце.

Archimedes Trajano 23.07.2024 13:57

Интересно, как правильно было бы набирать then, чтобы это прошло с implemented PromiseLike<void>

Archimedes Trajano 23.07.2024 14:06

Смотрите дополнение к ответу.

trincot 23.07.2024 16:03

Другие вопросы по теме