权宜之计
您可以创建一个async init() {... return this;}
方法,然后new MyClass().init()
在您通常只说new MyClass()
.
这并不干净,因为它依赖于使用您的代码的每个人以及您自己,总是像这样实例化对象。但是,如果您仅在代码中的一两个特定位置使用此对象,则可能没问题。
一个严重的问题发生了,因为 ES 没有类型系统,所以如果你忘记调用它,你只是返回,undefined
因为构造函数什么都不返回。oop。更好的是做这样的事情:
最好的做法是:
class AsyncOnlyObject {
constructor() {
}
async init() {
this.someField = await this.calculateStuff();
}
async calculateStuff() {
return 5;
}
}
async function newAsync_AsyncOnlyObject() {
return await new AsyncOnlyObject().init();
}
newAsync_AsyncOnlyObject().then(console.log);
// output: AsyncOnlyObject {someField: 5}
工厂方法解决方案(稍微好一点)
但是,您可能会不小心执行新的 AsyncOnlyObject,您可能应该创建Object.create(AsyncOnlyObject.prototype)
直接使用的工厂函数:
async function newAsync_AsyncOnlyObject() {
return await Object.create(AsyncOnlyObject.prototype).init();
}
newAsync_AsyncOnlyObject().then(console.log);
// output: AsyncOnlyObject {someField: 5}
但是,如果您想在许多对象上使用此模式……您可以将其抽象为装饰器或您在定义 like 后(详细地,呃)调用的东西postProcess_makeAsyncInit(AsyncOnlyObject)
,但在这里我将使用extends
它,因为它有点适合子类语义(子类是父类+额外的,因为它们应该遵守父类的设计契约,并且可以做额外的事情;如果父类不是异步的,一个异步子类会很奇怪,因为它不能被初始化相同大大地):
抽象解决方案(扩展/子类版本)
class AsyncObject {
constructor() {
throw new Error('classes descended from AsyncObject must be initialized as (await) TheClassName.anew(), rather than new TheClassName()');
}
static async anew(...args) {
var R = Object.create(this.prototype);
R.init(...args);
return R;
}
}
class MyObject extends AsyncObject {
async init(x, y=5) {
this.x = x;
this.y = y;
// bonus: we need not return 'this'
}
}
MyObject.anew('x').then(console.log);
// output: MyObject {x: "x", y: 5}
(不要在生产中使用:我没有考虑过复杂的场景,例如这是否是为关键字参数编写包装器的正确方法。)