Вы не можете использовать асинхронные операции в конструкторе. Проблема в том, что конструктор должен вернуть ваш экземпляр, поэтому он также не может вернуть обещание, которое сообщит вызывающей стороне, когда это будет сделано.
Итак, в вашем Consumers
классе await new Consumers();
не делает ничего полезного. new Consumers()
возвращает новый экземпляр Consumers
объекта, поэтому, когда вы await
, он фактически ничего не ждет. Помните, что await
делает с вами что-то полезное await
обещание. У него нет особых полномочий ждать завершения работы вашего конструктора.
Обычным способом решения этой проблемы является создание фабричной функции (которая может быть статической в вашем дизайне), которая возвращает обещание, которое разрешается для нового объекта.
Поскольку вы также пытаетесь создать синглтон, вы должны кэшировать обещание при первом его создании и всегда возвращать обещание вызывающей стороне, чтобы вызывающий всегда использовал .then()
для получения готового экземпляра. Когда они в первый раз позвонят, они получат обещание, которое еще не выполнено, но позже они получат обещание, которое уже выполнено. В любом случае они просто используют .then()
, чтобы получить экземпляр.
Я недостаточно хорошо знаю TypeScript, чтобы предложить вам реальный код для этого, но, надеюсь, вы поняли идею из описания. Превратите GetInstance()
в фабричную функцию, которая возвращает обещание (которое вы кэшируете) и которое разрешает это обещание для вашего экземпляра.
Примерно так:
static async GetInstance(): Promise<Consumers> {
if (!Consumers.promise) {
let obj = new Consumers();
Consumers.promise = obj.init().then(() => obj);
}
return Consumers.promise;
}
Тогда вызывающий абонент сделает:
Consumers.getInstance().then(consumer => {
// code here to use the singleton consumer object
}).catch(err => {
console.log("failed to get consumer object");
});
Вам придется делать то же самое в любом классе, в котором асинхронные операции также задействованы при инициализации объекта (например, CommandBus), и каждый вызов .init()
должен вызывать базовый класс super.init().then(...)
, чтобы базовый класс мог делать свое дело чтобы правильно инициализироваться, и обещание, что ваш .init()
также связано с базовым классом. Или, если вы создаете другие объекты, которые сами имеют фабричные функции, тогда ваш .init()
должен вызвать эти фабричные функции и связать их обещания вместе, чтобы возвращаемое обещание .init()
связывалось также с другими обещаниями фабричной функции ( поэтому обещание, которое ваши .init()
вернут, не разрешится, пока все зависимые объекты не будут выполнены).