【发布时间】:2021-03-21 21:05:35
【问题描述】:
在我的 mongoDB 数据库中,我有一个 Posts 模型,其中包含对 Comments 模型的引用数组。
对于我的 Express 应用程序中的一个 get 请求,我必须使用数据库中所有帖子的数组来响应,每个帖子都包含它拥有的所有 cmets 的数组
我选择这样做的方法是,使用 find 获取所有帖子,它返回所有帖子的数组,根据我的模型,每个帖子都包含对其拥有的 cmets 的引用数组。
为了解决这些引用,我选择了 mongoose 提供的填充方法,它根据它包含的引用从数据库中返回实际对象,这对于帖子来说非常简单
await post.populate("comments").execPopulate();
这里的帖子是单个帖子实例,在此操作之后,帖子实例包含解析为评论对象的所有评论引用
但要为每个帖子单独执行此操作,我尝试了两种方法,其中allPosts 是我在查找查询后获得的所有帖子的数组
- 使用上面的 execPopulate 操作,创建一个包含所有 promise 的数组,不管它们是否被解析,然后在全部解析后使用
Promise.all()执行进一步的操作
let promiseArray = allPosts.map( (post) => {
post.populate("comments").execPopulate();
});
Promise.all(promiseArray).then((posts) => {
// this map is another extra irrelevant operation I performed to
// format the response array in a particular way, where
// I had to remove extra fields in both the posts array
// as well as the populated comments array
let responseArray = posts.map((post) => {
return {
comments: filterComments(post.comments),
_id: post._id,
title: post.title,
commentcount: countComments(post.comments),
};
});
return res.send(responseArray);
});
- 我尝试的另一种方法是设置一个 while 循环,在其中我等待每个帖子在每次迭代中单独解析,然后将解析和格式化的帖子对象推送到一个数组(响应数组)中,完成后发送响应数组
let responseArray = [];
let length = allPosts.length;
let counter = allPosts.length;
while(counter) {
// get the first post because counter is reverse
let post = allPosts[length - counter]
// the population operation where every post array
// is populated with its comments
await post.populate('comments').execPopulate();
// push the filtered object to another array
responseArray.push({
comments : filterComments(post.comments),
_id : post._id,
title : post.title,
commentcount : countComments(post.comments),
})
counter --;
}
return res.send(responseArray);
应用程序在使用 while 循环解析单个 promise 时花费了三次时间来响应大约 150 个左右的同一组数据,并且当我将所有 promise 存储在数组中然后在 Promise.all() 中解析它们时速度更快, 我对 JS 事件循环不是很详细,所以想知道是否有什么原因导致这个
TL;DR:
我有一个要对数组中的每个元素执行的异步操作的列表,我试过了:
-
遍历数组将所有未解析的promise存储在数组中,然后在promise数组上使用
Promise.all()后做进一步的操作 -
遍历数组使用while循环,对每个元素执行异步操作在每次迭代中
while 循环花费几乎三倍的时间,Promise.all() 上的解析需要
【问题讨论】:
-
allPosts.map( (post) => { post.populate("comments").execPopulate(); });不会产生一个 promise 数组,而是一个undefined数组。所以Promise.all([undefined, undefined, /* .... */, undefined])基本会马上解决。 -
你应该在你的 map 方法中删除括号
{} -
无论如何,在循环中,您要等待每个操作完成,然后再进行下一个操作。哪个会先完成 - 一次设置三个计时器,每个计时器 1 分钟并等待所有人完成,或者将计时器设置为一分钟,一旦它再次完成,然后第三次?
-
不,它们并没有导致 undefined,而是 console.log 上的数组给出了一个 Promise(
) 数组 -
await在一个循环中按顺序运行所有填充调用。当然那更慢!
标签: javascript mongodb performance express promise