与 Promise.all() 中的解析相比,为啥在 while 循环中单独解析 Promise 数组时解析更慢? [复制]
Posted
技术标签:
【中文标题】与 Promise.all() 中的解析相比,为啥在 while 循环中单独解析 Promise 数组时解析更慢? [复制]【英文标题】:Why is resolution of array of promises slower when resolved individually in a while loop, compared to resolution in Promise.all()? [duplicate]与 Promise.all() 中的解析相比,为什么在 while 循环中单独解析 Promise 数组时解析更慢? [复制] 【发布时间】: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
在一个循环中按顺序运行所有填充调用。当然那更慢!
【参考方案1】:
我不是专业的 javascript 开发人员,但据我所知。
事件循环不会在单个线程上运行,因此在使用 Promise.all() 时,promise 会同时执行。 通常,使用 Promise.all() 会并行运行“异步”请求。 并行执行可以节省时间,这就是 Promise.all() 对于每个 Promise 都比 await 更快的原因。
注意: Promise 将在创建后执行。在您的代码中,您已经在 map 方法中创建了 Promise。
Promise.all 只是等待每个承诺得到履行。
相反,async/await 创建一个 promise 等待它然后创建另一个。
但是,您可以直接填充所有帖子的 cmets。使用 下面的代码,比这两种解决方案都快
const PostsWithComments = await PostsModel.find().populate("comments").exec()
【讨论】:
是的,我试过了,对于一个帖子来说很好,但是我需要为一系列帖子做这个,所以唯一的方法是在某个循环中,我用while 循环来做它Promise.all
不会引发并行性或多线程。 “承诺”也不是“任务”,它是一个待处理的值。该任务甚至可能根本不会在 JS 引擎中执行。例如,访问数据库,意味着您发出请求并等待从中获取结果,无需处理。
@Mayur populate 也适用于一系列帖子。 sn-p 也应该适用于多个帖子。您不需要为此进行后期操作。猫鼬会为你做的。
@RamanShekhawat 哦,从来没有想过要立即为整个阵列这样做,我想我会尝试并检查一下,不管这个问题如何,我仍然对为什么承诺速度较慢很感兴趣在while循环中解决
这不是准确的信息。以上是关于与 Promise.all() 中的解析相比,为啥在 while 循环中单独解析 Promise 数组时解析更慢? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript 中的 Promise.all:如何获得所有承诺的解析值?
为啥我的 apolloFetch 调用在从 promise.all 中调用时返回一个空查询?
为啥即使我 .catch() Promise.all() 也会抛出异常?