【发布时间】:2022-01-26 00:35:56
【问题描述】:
我正在修补 exec() 函数以允许在 Mongoose 中进行子填充,这就是为什么我不能在这里使用 async/await ——我的函数将被链接到一个 db 调用,所以没有机会调用 await在它上面,在子模块本身内,我不能在异步函数本身之外添加async/await。
不碍事,让我们看看我要做什么。我有两个单独的数组(matchingMealPlanFoods 和matchingMealPlanRecipeFoods),里面装满了我需要填充的 ID。它们都驻留在同一个数组foods 上。它们每个都需要一个带有聚合的 db 调用,而我当前场景中的问题是只有一个数组填充,因为它们是异步发生的。
我现在要做的是使用reduce 函数将更新后的食物数组返回到下一次运行reduce,这样当返回最终结果时,我可以替换整个foods 数组一次在我的doc 上。问题当然是我的aggregate/exec 在reduce 函数进入下一次运行时还没有返回值。没有async/await这里有没有办法实现这一点?我在这里包含了高级结构,以便您可以了解需要发生什么,以及为什么使用 .then() 可能不可行。
编辑:使用异步建议更新代码
function execute(model, docs, options, lean, cb) {
options = formatOptions(options);
let resolvedCount = 0;
let error = false;
(async () => {
for (let doc of docs) {
let newFoodsArray = [...doc.foods];
for (let option of options) {
const path = option.path.split(".");
// ... various things happen here to prep the data
const aggregationOptions = [
// // $match, then $unwind, then $replaceRoot
];
await rootRefModel
.aggregate(aggregationOptions)
.exec((err, refSubDocuments) => {
// more stuff happens
console.log('newFoodsArray', newFoodsArray); // this is to check whether the second iteration is using the updated newFoods Array
const arrToReturn = newFoodsArray.map((food) => {
const newMatchingArray = food[nests[1]].map((matchingFood) => {
//more stuff
return matchingFood;
});
const updatedFood = food;
updatedFood[`${nests[1]}`] = newMatchingArray;
return updatedFood;
});
console.log('arrToReturn', arrToReturn);
newFoodsArray = [...arrToReturn];
});
}
};
console.log('finalNewFoods', newFoodsArray); // this should log after the other two, but it is logging first.
const document = doc.toObject();
document.foods = newFoodsArray;
if (resolvedCount === options.length) cb(null, [document]);
}
})()
编辑:因为它似乎会有所帮助,所以这是我在上面摘录的调用 execute 函数的内容。
/**
* This will populate sub refs
* @param {import('mongoose').ModelPopulateOptions[]|
* import('mongoose').ModelPopulateOptions|String[]|String} options
* @returns {Promise}
*/
schema.methods.subPopulate = function (options = null) {
const model = this.constructor;
if (options) {
return new Promise((resolve, reject) => execute(model, [this], options, false, (err, docs) => {
if (err) return reject(err);
return resolve(docs[0]);
}));
}
Promise.resolve();
};
};
【问题讨论】:
-
我不明白你在这里做什么。在外部循环的每次迭代结束时,您都会创建一个
document对象,但如果它不是最后一次迭代,您的代码不会对document执行任何操作,并且它会立即脱离其(块)范围,以及newFoodsArray,这样信息就丢失了。 -
.reduce()确实与异步操作不太兼容,因为它的循环是同步的,从不暂停异步操作。 -
你为什么要避开
async/await?它被添加到语言中是因为它大大简化了异步编程。这就像你有一个任务要敲钉子,有人递给你锤子,而你拒绝使用专为这项工作设计的工具。 -
@trincot 这不是完整的模块文件。我在第一段中提到我正在修补 Mongoose 命令(实际上我正在做的是扩展/修改第 3 方库)。如果有帮助,我已经添加了直接调用执行的函数。
-
@jfriend00 我在第一段中解释了为什么我不能使用 async/await——如果函数本身不是异步函数,你就不能使用它们,我不能如果它链接到 Mongoose 命令,则它是一个异步函数。
标签: javascript node.js asynchronous async-await reduce