Javascript异步实例化和私有构造函数



我需要异步实例化一个对象。但是构造函数方法不能被声明为asyncasync constructor(){},也不能像async new MyClass()那样被调用。无论如何,这都会很奇怪。因此,需要某种类型的工厂。我还想隐藏构造函数。如果构造函数可以被声明为private:#constructor,那么这将非常容易实现。但即使有ES2022私有类功能,这也是不可能的。然而,有几种模式可以解决这两个问题。我将列出其中的3个(在ES6模块的上下文中(。

我想知道哪种模式(如果有的话(被认为是好的,哪种不好。或者,如果有更好的解决方案,请告诉我。

方法一:静态布尔值(无工厂(

let calledInit = false;
export default class MyClass {
constructor(data) {
if (calledInit === false)
throw Error('private constructor');
calledInit = false;
// member initializations here
}
static async initialize() {
calledInit = true;
// do some async stuff here
return new MyClass(data);
}
}

方法二:闭包和单例工厂

const MyClass = (function() {
class MyClass {
constructor(data) {
// member initializations here
}
}
return {
initialize: async function() {
// do some async stuff here
return new MyClass(data);
}
}    
})();
Object.freeze(MyClass);
export default MyClass;

像这样使用它们:

const obj = await MyClass.initialize();

方法三:工厂功能

class MyClass {
constructor(data) {
// member initializations here
}
}
export default async function MyClassInitializer() {
// do some async stuff here
return new MyClass(data);
} 

像这样使用:

const obj = await MyClassInitializer();

编辑:为了澄清,我认为隐藏构造函数是有益的。主要用于调试。假设构造函数是公共的,而其他人正在使用新运算符实例化对象。它总是以模糊的错误消息失败,她/他无法理解。所有这一切,因为她/他没有仔细阅读文档,其中明确说明使用initialize((方法创建实例。这本来可以很容易地通过隐藏构造函数来防止。

免责声明这是我的观点

异步实例化对象并不是一件有充分理由的事情。

构造函数的目的是构造您的对象。不应该在构造函数中放入诸如文件、API等的加载操作。

将它们放入一个单独的函数中,并将结果用作类的参数。

async () => {
const data = await fetch(...) // get data / do some sideeffect
const myObject = new MyObject(data)
}

这通常也是可取的,因为您可以更新一些状态来跟踪请求的进度。或者,您可能希望缓存它并在多个位置使用它。

async () => {
state = "LOADING"
const data = await fetch(...) // get data / do some sideeffect
state = "SUCCESS"
const myObject = new MyObject(data)
}

隐藏构造函数并不是真正需要的,因为当你不向它传递数据时会出现错误。类的用户应该知道要传递什么。如果你使用typescript,这将更加严格。

当然,您可以像方法3中那样将其放在一个初始化函数中。

最新更新