使用Mongoose的findOne时,回调外变量赋值后为undefined
嘿,这个问题我当初刚上手Mongoose的时候也踩过一模一样的坑!核心原因是Mongoose的findOne是异步操作,代码不会等着回调函数执行完才往下走,所以你在回调外面访问变量时,它还没被赋值呢。
先把你的代码片段整理出来,方便看清楚问题:
var MessageSchema = mongoose.Schema({ code: String, to: String, body: ... // 省略的字段内容 }); var Message= mongoose.model('Message', MessageSchema); mongoose.connect('mongodb://localhost/test'); var msg; Message.findOne({"code": 123}, function(err, message){ msg = message; // 这里把查询结果赋值给msg }); console.log(msg); // 这里会输出undefined!
为什么会出现这个问题?
Node.js是异步非阻塞的,当你调用Message.findOne()时,它会把这个数据库查询任务放到事件队列里,然后立刻继续执行后面的console.log(msg)。这时候回调函数还没被触发,msg还是你一开始声明的undefined状态。
几种解决方案
1. 把逻辑放在回调函数内部(最直接)
所有需要用到查询结果的代码,都写在回调函数里:
var msg; Message.findOne({"code": 123}, function(err, message){ if (err) { // 一定要处理错误!不然出问题都不知道为啥 console.error('查询出错:', err); return; } msg = message; // 所有依赖msg的操作都放这里 console.log(msg); // 这里能正常拿到值 processMessage(msg); // 比如调用其他函数处理消息 });
2. 使用Promise + .then()链式调用
Mongoose从4.0版本开始原生支持Promise,你可以用链式调用让代码更清晰:
// 旧版本Mongoose需要手动指定Promise(新版本可省略) mongoose.Promise = global.Promise; Message.findOne({"code": 123}) .then(function(message) { var msg = message; console.log(msg); // 在这里处理查询结果 }) .catch(function(err) { console.error('查询失败:', err); });
3. 使用async/await(推荐,代码最简洁)
这是ES6+的语法,需要把逻辑放在async函数里,代码看起来像同步的一样:
// 封装成async函数 async function getTargetMessage() { try { // 建议把数据库连接放在应用启动处,不要每次查询都连 await mongoose.connect('mongodb://localhost/test'); var msg = await Message.findOne({"code": 123}); console.log(msg); // 在这里处理msg的逻辑 } catch (err) { console.error('操作出错:', err); } } // 调用函数 getTargetMessage();
额外提醒
- 永远不要忽略错误处理!不管是回调里的
err参数,还是Promise的catch,或是async/await的try/catch,错误处理能帮你快速定位问题。 - 数据库连接最好放在应用的入口初始化代码里,不要每次查询都重新连接一次,浪费资源。
内容的提问来源于stack exchange,提问作者notExactlyAHero
相关产品推荐
相关产品推荐

