await仅在async函数中有效:computeAggregate无法等待fetchRecords的Promise
问题分析与修复方案
你遇到的核心问题是**await被用在了一个非async的回调函数里**,而且就算给回调加async,外层的computeAggregate也无法等待回调内的异步操作完成。咱们一步一步解决:
为什么原来的代码报错?
你在model.collection.distinct的普通回调函数里使用了await,但这个回调并没有被标记为async——JS严格要求await只能出现在async函数内部,所以直接触发报错。
更糟的是,就算你把回调改成async function(error, distMinutes) {...},外层的computeAggregate函数也不会等待这个回调里的所有异步逻辑执行完毕,因为回调是异步触发的,外层函数会直接走完流程,导致你的聚合逻辑无法按预期完成。
修复后的代码(顺序执行版本)
我们把model.collection.distinct改成Promise形式(Mongoose的大部分方法都支持Promise,不用非得用回调),然后在async函数的主逻辑里使用await,同时用for...of遍历数组(比for...in更安全,避免遍历到原型链上的属性):
const computeAggregate = async (model, sym) => { try { // 改用Promise形式获取distinct结果,替代回调写法 const distMinutes = await model.collection.distinct("minutes_offs", { symbol: sym }); // 用for...of遍历,支持在循环内使用await顺序执行 for (const minuteOff of distMinutes) { console.log("inside minutes off", minuteOff); const records = await fetchRecords(model, sym, minuteOff); const aggData = getAggregateData(records); createCollection(aggData); } } catch (error) { console.log("error in computeAggregate", error); } } const fetchRecords = async (model, sym, minutesOff) => { console.log("compute function : input param", sym, minutesOff); const query = model.find({ symbol: sym, minutes_offs: minutesOff }).sort({ minutes_offs: +1 }); return query.exec(); };
可选优化:并行执行版本
如果你的业务场景不需要严格按顺序处理每个minuteOff,可以用Promise.all并行发起所有请求,大幅提高效率:
const computeAggregate = async (model, sym) => { try { const distMinutes = await model.collection.distinct("minutes_offs", { symbol: sym }); // 并行处理所有异步任务 await Promise.all(distMinutes.map(async (minuteOff) => { console.log("inside minutes off", minuteOff); const records = await fetchRecords(model, sym, minuteOff); const aggData = getAggregateData(records); createCollection(aggData); })); } catch (error) { console.log("error in computeAggregate", error); } }
这样所有fetchRecords请求会同时触发,适合对执行顺序没有要求的场景。
内容的提问来源于stack exchange,提问作者user2130951
相关产品推荐
相关产品推荐

