简体   繁体   English

如何避免在循环中等待

[英]How to avoid await inside a loop

I have the following code:我有以下代码:

const data = res?.advancedResult?.data;
for (const referential of data) {
    const entities = await EntityDAO.find({ query: { referential: referential?._id } });
    for (const entity of entities) {
        const items = await ItemDAO.find({ query: { entity: entity?._id } });
        entity.items = items.length;
    }
    referential.entities = entities.map(entity => ({ name: entity.name, items: entity.items }));
}

Since I'm using eslint I got the following error:由于我使用的是 eslint,因此出现以下错误:

[eslint] Unexpected `await` inside a loop. (no-await-in-loop)

I can't use Promise.all since the iterations of a loop are not actually independent of each-other.我不能使用Promise.all因为循环的迭代实际上并不相互独立。
Is there anyway to avoid the await insid the loop so i can boost the performance?有没有办法避免循环内部的等待,这样我就可以提高性能? or i just should silence the error by adding /* eslint-disable no-await-in-loop */或者我应该通过添加/* eslint-disable no-await-in-loop */错误

It seems that you are suffering from the classic "N+1 Selects" problem.看来您正遭受经典的“N+1 选择”问题。 There are several ways to go about it - the last one being preferable:有几种方法可以 go 关于它 - 最后一种更可取:

  • If the performance isn't an issue, just leave it as it is, and try to contest your eslint rules instead.如果性能不是问题,请保持原样,并尝试挑战您的 eslint 规则。 After all, somebody did set that rule.毕竟,确实有人制定了这条规则。 Ask that person why that is and what problem they were trying to solve with it - maybe there's hidden wisdom behind it.问那个人为什么会这样,他们试图用它解决什么问题——也许它背后隐藏着智慧。
  • You could parallelize the loading of Items (the inner loop), so that the Items of all Entities are loaded concurrently.您可以并行加载项目(内部循环),以便同时加载所有实体的项目。 However, you run the risk of getting unbounded concurrency - if the first query gets 100 Entities, you then launch 100 queries in parallel.但是,您冒着获得无限并发的风险 - 如果第一个查询获得 100 个实体,那么您将并行启动 100 个查询。 Guard against that (see modules like p-limit ).提防这种情况(请参阅诸如p-limit类的模块)。
  • You can construct flatter queries: get all Entities, gather their IDs and build a big query that amalgamates the IDs.您可以构建更扁平的查询:获取所有实体,收集它们的 ID 并构建一个合并 ID 的大查询。 I'm not sure what DB you're using, but you're looking for the equivalent of an SQL WHERE entity IN (value1, value2, ...) .我不确定您使用的是什么数据库,但您正在寻找相当于 SQL WHERE entity IN (value1, value2, ...)的数据库。 Then, once you've got all the Items, iterate over them and assign each to its parent Entity.然后,一旦你得到了所有的项目,迭代它们并将每个分配给它的父实体。 This way, you only get 2 queries (at the cost of more client-side complexity).这样,您只能获得 2 个查询(以增加客户端复杂性为代价)。

Overall, it's best to tackle the actual problem (N+1 queries), instead of bending async code to implement it.总的来说,最好解决实际问题(N+1 个查询),而不是弯曲异步代码来实现它。 If you're writing something similar to an ORM, it may be worthwhile to explore existing implementations and how they deal with this well-researched issue.如果您正在编写类似于 ORM 的东西,那么探索现有的实现以及它们如何处理这个经过充分研究的问题可能是值得的。

Maybe you could use a map function, a map function is async and can await.也许你可以使用 map function、map ZC1C425268E683854D1AB5074C17 和等待。

const data = res?.advancedResult?.data;
const temp = data.map(async(referential)=>{
    return await EntityDAO.find({ query: { referential: referential?._id } 
});

add here the rest...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM