Node.js新手求助:使用回调获取MongoDB查询结果失败
解决MongoDB数据获取异步问题的方案
别担心,新手遇到异步问题太正常啦!你的核心问题是Node.js里MongoDB的操作是异步的,但你的list函数是同步返回数组,所以当你调用list()的时候,数据库查询还没完成,自然拿不到预期的数据。
先拆解你的代码问题点:
var list=()=>{ var arr=[] var blQ={blocked_user:data.tag_search_mail} db.collection("block_list").find(blQ,{"_id":0}).toArray((err,res)=>{ for(let i=0;i<res.length;i++){ arr.push(res[i]["blocker"]) } }); return arr // 这里会直接返回空数组,因为toArray的回调还没执行! }
toArray是异步函数,它的回调会在数据库查询完成后才触发,但你的list函数不等这个回调结束,直接就返回了空的arr,这就是你拿不到数据的原因。
下面给你三种从简单到现代的解决方案:
方法1:用回调函数传递结果
把后续要执行的逻辑(比如你的showList)作为回调传给list,让异步操作完成后再调用:
var list=(callback)=>{ var blQ={blocked_user:data.tag_search_mail} db.collection("block_list").find(blQ,{"_id":0}).toArray((err,res)=>{ if(err) return callback(err); // 别忘了处理错误 var arr = [] for(let i=0;i<res.length;i++){ arr.push(res[i]["blocker"]) } callback(null, arr); // 查询完成后把数组传给回调 }); } // 调用的时候 list((err, resultArr) => { if(err) { console.error("查询出错:", err); return; } console.log("拿到的数据:", resultArr); // 在这里调用你的showList函数 showList(resultArr); });
方法2:用Promise封装异步操作
用Promise把数据库查询包起来,这样可以用.then()链式处理结果,代码结构更清晰:
var list=()=>{ return new Promise((resolve, reject) => { var blQ={blocked_user:data.tag_search_mail} db.collection("block_list").find(blQ,{"_id":0}).toArray((err,res)=>{ if(err) return reject(err); // 用map替代for循环,代码更简洁 var arr = res.map(item => item["blocker"]); resolve(arr); }); }); } // 调用的时候 list() .then(resultArr => { console.log("拿到的数据:", resultArr); showList(resultArr); }) .catch(err => { console.error("查询出错:", err); });
方法3:用async/await(最推荐,代码像同步一样好读)
这是现代Node.js最常用的写法,让异步代码看起来和同步逻辑一致:
// 把list改成async函数 var list=async()=>{ var blQ={blocked_user:data.tag_search_mail} // await会等待数据库查询完成(新版MongoDB驱动的toArray本身返回Promise) var res = await db.collection("block_list").find(blQ,{"_id":0}).toArray(); var arr = res.map(item => item["blocker"]); return arr; } // 调用时需要在async函数里用await async function run() { try { var resultArr = await list(); console.log("拿到的数据:", resultArr); showList(resultArr); } catch(err) { console.error("查询出错:", err); } } run();
最后提两个小细节:
- 别直接
throw err,生产环境里建议用更友好的错误处理逻辑 - 新版MongoDB驱动(v4+)里,
MongoClient.connect也支持Promise/async/await,你可以把数据库连接逻辑也改成异步的,避免多层回调嵌套
内容的提问来源于stack exchange,提问作者Srinivas Nahak
相关产品推荐
相关产品推荐

