Без использования общих шаблонов «инициализации» или «построителя»

Создание объекта класса: общепринятые методы

init и builder - два метода, которые я чаще всего рекомендую для создания объекта класса, который требует асинхронного процесса.

Экземпляр init ()

class MyClass {
  constructor() {
    // set props normally
    // nothing async can go here
  }
  public async init() {
    // do your async steps here
  }
}

Метод init - это метод, в котором вы определяете метод экземпляра async, выполняя всю вашу async настройку в качестве дополнительного шага после создания экземпляра объекта.

const myClassInstance = new MyClass()
// need to remember to call this on the instance
await myClassInstance.init()

Проблема, с которой я сталкиваюсь с этим подходом, заключается в том, что вы должны быть уверены, что вызывающий объект, создающий класс, помнит о вызове метода init() всякий раз, когда создается экземпляр класса. Это, очевидно, подвержено ошибкам и требует, чтобы у вызывающей стороны был этот контекст о классе.

Построитель объектов класса

class MyClass {
  constructor() {
    // set props normally
    // nothing async can go here
  }
  public static async build(): Promise<MyClass> {
    // do your async stuff here
    // now instantiate and return a class
    return new MyClass()
  }
}

Метод построителя объекта класса немного лучше. Этот подход также используется в других языках как своего рода обходной путь. Он включает в себя написание статического метода для объекта класса, который выполняет асинхронную обработку перед синхронным созданием экземпляра объекта класса и его возвратом.

const myClassInstance = await MyClass.build()

Мне этот подход нравится больше, чем предыдущий, поскольку он снижает нагрузку на вызывающего абонента, который не может забыть вызвать дополнительную init() функцию. Однако вызывающей стороне по-прежнему необходимо иметь контекст для использования нестандартного статического метода класса для создания экземпляра класса вместо стандартного синтаксиса new MyClass(). Невозможно сделать конструктор закрытым или избежать этой простой ошибки. РЕДАКТИРОВАТЬ: это по-прежнему верно для Javascript, но Typescript 2.x действительно предоставляет частные / защищенные декораторы для метода конструктора класса, который будет обеспечивать, чтобы только метод «build» мог создать экземпляр класса. Добавьте это к длинному списку причин использовать Typescript вместо Javascript;)

Шаблон функциональных опций

Я уже писал ранее о том, как можно использовать шаблон функциональных опций для чистого построения классов:



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

Конструктор асинхронных опций

Ниже представлено расширение моего предыдущего House класса-примера, которое я использовал для демонстрации построения с помощью функциональных опций. Как видите, все, что нужно для создания асинхронного режима, - это создание конструктора параметров async:

Принятие шаблона функциональных опций для построения классов имеет другие преимущества, но, в частности, позволяет создавать объект класса, для которого могут потребоваться асинхронные процессы. Вызов асинхронной функции можно добавить прямо на этапе создания экземпляра класса, не требуя отдельного init() вызова или изменения установленного вами метода построения класса. Вызывающие могут использовать стандартный синтаксис new House() для создания экземпляра класса и использовать установленный вами шаблон конструкторов статических классов для создания своего экземпляра объекта без необходимости в дополнительном контексте реализации класса.

Удачного кодирования!