我需要通过调用函数从集合“用户”中获取用户ID并返回其值。
fetchId = (name) => {
User.findOne({name: name}, (err, user) => {
return user._id;
});
};
但是此实现返回null。解决该问题的方法是什么?
答案 0 :(得分:3)
在您的示例之后,如果您不想使用Promise,您可以简单地传递来自调用方的回调,并在得到结果后调用该回调,因为对mongo的调用是异步的。
fetchId = (name, clb) => {
User.findOne({name: name}, (err, user) => {
clb(user._id);
});
};
fetchId("John", id => console.log(id));
否则,您可以使用基于承诺的机制,省略第一个回调,并将承诺返回给调用方。
fetchId = name => {
return User.findOne({name: name}).then(user => user.id);
};
fetchId("John")
.then(id => console.log(id));
答案 1 :(得分:0)
第三种方法是@Karim的(非常好)答案中建议2的变体。如果OP希望对它进行编码,就好像从异步代码中分配了结果,则可以将fetchId声明为async
并将其结果await
声明为一个改进...
fetchId = async (name) => {
return User.findOne({name: name}).then(user => user.id);
};
let someId = await fetchId("John");
console.log(id)
修改
对于对象上的任何方法-包括属性获取器-都是异步工作的,调用代码需要意识到并采取相应的行动。
这倾向于在您的系统中扩展到依赖于呼叫者的呼叫者的任何事物,依此类推。我们无法避免这种情况,并且没有语法修复(语法是编译器看到的)。这是物理学:需要更长的时间,只是需要更长的时间。我们可以使用语法来部分掩盖复杂性,但是我们被额外的复杂性所困。
将其应用于您的问题,假设我们有一个代表用户的对象,该对象由mongo远程存储。最简单的方法是在异步获取(findOne)操作完成之前将内存中的用户对象视为未就绪。
在这种方法下,调用者只需记住一件事:告诉未准备就绪的用户在使用前做好准备。下面的代码采用了async / await风格的语法,这是最现代的,并且可以最大程度地隐藏-但不能消除:-(-异步复杂性...
class MyMongoUser {
// after new, this in-memory user is not ready
constructor(name) {
this.name = name;
this.mongoUser = null; // optional, see how we're not ready?
}
// callers must understand: before using, tell it to get ready!
async getReady() {
this.mongoUser = await myAsyncMongoGetter();
// if there are other properties that are computed asynchronously, do those here, too
}
async myAsyncMongoGetter() {
// call mongo
const self = this;
return User.findOne({name: self.name}).then(result => {
// grab the whole remote object. see below
self.mongoUser = result;
});
}
// the remaining methods can be synchronous, but callers must
// understand that these won't work until the object is ready
mongoId() {
return (this.mongoUser)? this.mongoUser._id : null;
}
posts() {
return [ { creator_id: this.mongoId() } ];
}
}
请注意,我们丢弃了整个mongo对象,而不仅仅是从用户那里抢走mongo _id
。除非这是一个巨大的内存消耗,否则我们最好将其挂起,以便获得任何远程存储的属性。
这里是呼叫者的样子...
let joe = new MyMongoUser('joe');
console.log(joe.posts()) // isn't ready, so this logs [ { creator_id: null } ];
await joe.getReady();
console.log(joe.posts()) // logs [ { creator_id: 'the mongo id' } ];