Express+MongoDB获取集合数据时Promise提前Resolve问题求助
解决Express+MongoDB异步循环获取集合数据的时序问题
你的问题核心是同步循环里的异步操作没有被正确等待——find({}).toArray()是异步执行的,循环会快速走完,而这些异步查询还没返回结果,你就提前调用了resolve(allCols),自然会出现日志顺序颠倒、返回空数组的情况。
解决方案:用Promise.all()等待所有异步查询完成
MongoDB的大部分方法已经原生支持Promise,我们可以把每个集合的查询操作转换成Promise,然后用Promise.all()统一等待所有操作完成后再resolve最终结果。
修改后的getColAsync方法如下:
async getColAsync() { try { const db = await this.connectDB(); const dbase = db.db(this.databaseName); // 获取所有集合名称 const collectionNames = await dbase.listCollections().toArray(); // 把每个集合的查询操作转换成Promise,收集到数组中 const collectionPromises = collectionNames.map(col => { return dbase.collection(col.name.toString()).find({}).toArray(); }); // 等待所有Promise完成,得到所有集合的数据数组 const allCols = await Promise.all(collectionPromises); console.log("done getting all data"); return allCols; } catch (err) { console.log(err); throw err; // 把错误抛出,让调用方处理 } }
为什么这样能解决问题?
await替代回调:用await等待connectDB()和listCollections().toArray()的结果,避免嵌套回调的混乱。map生成Promise数组:遍历集合名称,每个集合的find({}).toArray()会返回一个Promise,我们把这些Promise都放进collectionPromises数组。Promise.all()统一等待:这个方法会等待数组里所有Promise都成功resolve后,才会返回一个包含所有结果的数组,顺序和原Promise数组一致,这样就能保证所有集合数据都获取完成后再返回。
另外,你的connectDB方法也可以改成更简洁的async/await风格(可选):
async connectDB() { if(this.dbConnection) { return this.dbConnection; } try { const db = await mongoClient.connect(this.URL); console.log("DB Access: resolved."); this.dbConnection = db; return db; } catch (err) { console.log("DB Access: Error on mongoClient.connect."); console.log(err); throw err; } }
这样修改后,日志顺序就会变成先输出每个集合的数据,最后输出done getting all data,而且返回的allCols会包含所有集合的完整数据。
内容的提问来源于stack exchange,提问作者noobcoder
相关产品推荐
相关产品推荐

