我正在实现一个批量获取和处理请求的查询引擎。我正在使用async / await。
现在,执行流程按层次结构运行,在该层次结构中有包含查询的项目列表,并且每个查询都具有访存权限。
我想做的是将项目捆绑在n个组中,因此,即使每个项目中都有m个带有内部提取的查询,也只能同时运行n * m个请求;并且特别地,只会向同一域同时发出一个请求。
问题是,当我等待项目执行时(在外部级别,将项目分组并在一段时间内将停止迭代,直到promise分解),当推迟执行内部查询时,这些promise就会解决。因为提取的内在等待。
这导致我的排队时间只是暂时停止,而不是等待内部承诺解决。
这是外部排队类:
class AsyncItemQueue {
constructor(items, concurrency) {
this.items = items;
this.concurrency = concurrency;
}
run = async () => {
let itemPromises = [];
const bundles = Math.ceil(this.items.length / this.concurrency);
let currentBundle = 0;
while (currentBundle < bundles) {
console.log(`<--------- FETCHING ITEM BUNDLE ${currentBundle} OF ${bundles} --------->`);
const lowerRange = currentBundle * this.concurrency;
const upperRange = (currentBundle + 1) * this.concurrency;
itemPromises.push(
this.items.slice(lowerRange, upperRange).map(item => item.run())
);
await Promise.all(itemPromises);
currentBundle++;
}
};
}
export default AsyncItemQueue;
这是队列正在运行的简单项目类。我省略了多余的代码。
class Item {
// ...
run = async () => {
console.log('Item RUN', this, this.name);
return await Promise.all(this.queries.map(query => {
const itemPromise = query.run(this.name);
return itemPromise;
}));
}
}
这是项目中包含的查询。每个项目都有一个查询列表。再次,一些代码被删除,因为它不有趣。
class Query {
// ...
run = async (item) => {
// Step 1: If requisites, await.
if (this.requires) {
await this.savedData[this.requires];
}
// Step 2: Resolve URL.
this.resolveUrl(item);
// Step 3: If provides, create promise in savedData.
const fetchPromise = this.fetch();
if (this.saveData) {
this.saveData.forEach(sd => (this.savedData[sd] = fetchPromise));
}
// Step 4: Fetch.
const document = await fetchPromise;
// ...
}
}
AsyncItemQueue
中的while正确停止,但是直到执行流程到达Query
中的步骤3为止。一旦到达标准抓取功能的包装程序即抓取操作,外部答应就会解决,最终我将同时执行所有请求。
我怀疑问题出在Query类中,但是我对如何避免外部承诺的解决感到困惑。
我尝试使Query
类run
函数返回文档,以防万一,但无济于事。
任何想法或指导将不胜感激。我将尝试回答有关代码的任何问题,或者在需要时提供更多问题。
谢谢!
PS:这是一个带有示例的代码框:https://codesandbox.io/s/goofy-tesla-iwzem
正如您在控制台出口中看到的那样,while循环在提取完成之前进行迭代,并且它们都在同一时间执行。
答案 0 :(得分:1)
我已经解决了。
问题出在AsyncItemQueue
类中。具体来说:
itemPromises.push(
this.items.slice(lowerRange, upperRange).map(item => item.run())
);
那是将承诺列表推入列表,因此,稍后:
await Promise.all(itemPromises);
在该列表中未找到任何等待的诺言(因为它包含更多列表,其中包含诺言)。
解决方案是将代码更改为:
await Promise.all(this.items.slice(lowerRange, upperRange).map(item => item.run()));
现在它运行良好。项目以n的批次运行,并且新的批次将在之前的批次完成之前运行。
我不确定这是否会帮助我,但我会把它留在这里,以防某天有人发现类似问题。感谢您的帮助。