我正在使用Node进行一个项目,Node是一种我不太熟悉的语言。
在项目中,我有一个类负责将数据读取和写入数据库(在本例中为LevelDB)。理想情况下,我想在构造函数中同步设置数据库连接,以使方法(writeItem,readItem等)的调用速度不会太快。换句话说,我不希望构造函数返回并允许下一行代码运行,直到所有的诺言都兑现。
我认为我要么缺少该语言的基础知识,要么在节点中有一些我不知道的设计模式。同样失败的玩具示例在这里:
class AClass {
constructor(n) {
this.name = n;
console.log('calling init.');
this.init();
console.log('init returned.');
}
func() {
return new Promise(resolve => {
setTimeout(() => {
resolve(true);
}, 2000);
});
}
async init() {
console.log('calling func()');
let x = await this.func();
console.log('after func(): ');
}
}
let x = new AClass('test');
console.log(JSON.stringify(x));
这将产生输出:
calling init.
calling func()
init returned.
{"name":"test"}
after func():
这令我惊讶。我本来期望:
calling init.
calling func()
after func():
init returned.
{"name":"test"}
最终目标是实例化一个连接到levelDB实例的类,并且在建立该连接之前不返回该对象。因此,代码可能看起来像这样:
let storage = new StorageObject();
storage.addItem(key, value); // <-- this fails unless StorageObject
// finishes the db setup.
谢谢! 山姆
答案 0 :(得分:3)
您的目标是直到连接失效后才返回实例(至少不是这样)。构造函数的工作是创建一个实例并返回该实例。函数需要同步返回 something 。如果它正在执行一些异步操作,则函数可以返回一个Promise,但是您不希望构造函数提供Promise —您需要实例。
执行此操作的简单方法是要求在创建对象后对其进行初始化,然后构造函数可以构造并返回实例,而init
函数可以自由返回诺言:
class AClass {
constructor(n) {/* some setup */}
func() {
return new Promise(resolve => {
setTimeout(() => {
resolve("some name");
}, 1000);
});
}
async init() {
this.name = await this.func();
return this
}
}
new AClass('test').init()
.then((initialized_obj) => console.log(initialized_obj))
如果在节点中执行此操作,则还可以使用eventEmitters在实例初始化后发出事件。像这样:
const EventEmitter = require('events');
class AClass extends EventEmitter{
constructor(n) {
super()
this.init()
.then(() => this.emit("initialized"))
}
func() {
return new Promise(resolve => {
setTimeout(() => {
resolve("some name");
}, 1000);
});
}
async init() {
this.name = await this.func();
return this
}
}
let x = new AClass('test')
x.on('initialized', () => console.log(x.name))
答案 1 :(得分:0)
关于代码的两件事:
this.init()
)时,它将一直执行直到它返回的await语句,然后将返回promise,控件将转到下一行(console.log('init returned.')
)。了解这一点将解决您的困惑。console.log('after func(): ');
)仅在等待的诺言已经解决后才执行。我已将您的代码重新用于您想要做的事情。
async function AClass(n) {
let obj = {}
obj.func = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve(true);
}, 2000);
});
};
obj.init = async function () {
console.log('calling func()');
let x = await obj.func();
console.log('after func(): ');
};
obj.name = n;
console.log('calling init.');
await obj.init();
console.log('init returned.');
return obj;
}
let x = AClass('test');
x.then((resolveValue) => {
/*
*Now the "class" has been instantiated,
* code to use the object of the "class" goes here
* */
console.log(JSON.stringify(resolveValue));
});
答案 2 :(得分:0)
如果您确实希望构造函数同步返回有效的AClass
,则可以通过稍微重写代码的其他部分来实现。我假设方法writeItem
,readItem
等是异步的。您所要做的就是重写这些方法,以便它们在继续操作之前等待对象初始化(如有必要)。
例如,假设您的课程如下所示:
class AClass {
constructor(n) {
this.name = n;
this.init();
}
async init() {
...
}
async writeItem(item) {
return await db.writeItem(item);
}
async readItem(itemId) {
return await db.readItem(itemId);
}
}
然后您应该能够按照以下方式对其进行重写:
class AClass {
constructor(n) {
this.name = n;
this.awaitInit = this.init();
}
async init() {
...
}
async writeItem(item) {
await this.awaitInit;
return await db.writeItem(item);
}
async readItem(itemId) {
await this.awaitInit;
return await db.readItem(itemId);
}
}