我正在尝试使用Promise.all函数来处理递归结构。
从for循环中调用的函数也可以创建promise,但是Promise.all
函数似乎在工作完成之前就完成了,我不知道为什么。
this.promised = [];
parseItem( relation ) {
if( relation.wasResolved === true ) {
return Promise.resolve();
}
return new Promise(async (resolve) => {
console.log( 'Parsing ' + relation.displaytitle );
let result = await this.MediaWiki.ask('[[Has source element::'+ relation.fulltext +']]|?Has target element');
// Loop over the API results
for( let k in result ) {
let targetElements = result[k].printouts['Has target element'];
// Loop over every target element
for( let index in targetElements) {
let itemIndex = this.getIndex( targetElements[index] );
// Only resolve known elements
if( itemIndex !== -1 ) {
// Set parent && resolve childs
this.elementsInView[itemIndex].parent = relation;
// Resolve
this.promised.push( this.parseItem( this.elementsInView[itemIndex] ) );
}
}
}
// Set wasResolved to true
relation.wasResolved = true;
resolve(true);
});
}
update() {
// Loop over every element in the view
for( let index in this.elementsInView ) {
let element = this.elementsInView[index];
// If the viewItem has a assigned hostId, add it to the queue
if( element.host !== -1 ) {
this.promised.push( this.parseItem( element ) );
}
}
Promise.all(this.promised).then(value =>{
this.finalize();
});
}
finalize() {
for( let index in this.elementsInView ) {
let element = this.elementsInView[index];
if( element.wasResolved === true ) {
console.log( element );
}
}
}
答案 0 :(得分:1)
问题来自于您尝试在this.promised
之间共享update()
以及parseItem()
内的异步行为。
要解决此问题,您可以从代表内部创建的每个Promise
的{{1}}返回parseItem()
。
例如,简化版本:
Promise
正如您所看到的,在async parseItem(relation) {
const result = await ask(relation);
return await Promise.all(result.map(i => {
const relations = i.relations;
return Promise.all(relations.map(parseItem));
}));
}
内,我们会在解决parseItem()
之前等待所有内容递归。
要将此应用于您的代码,它可能如下所示:
Promise
但是,我无法保证这会奏效。这取决于这个数据结构的性质以及在解决所有这些承诺的同时修改它的效果。
提出问题的主要问题是这一行:
async parseItem(relation) {
if (relation.wasResolved === true) {
return true;
}
console.log('Parsing ' + relation.displaytitle);
const result = await this.MediaWiki.ask('[[Has source element::' + relation.fulltext + ']]|?Has target element');
const nestedPromises = result.map(el => {
const targetElements = el.printouts['Has target element'];
// This returns an array of an array of promises
return targetElements
.map(tel => this.getIndex(tel))
.filter(index => index !== -1)
.map(index => {
this.elementsInView[index].parent = relation;
// This returns a promise
return this.parseItem(this.elementsInView[index]);
});
});
// Easy way to flatten array of arrays
const promises = [].concat.apply([], nestedPromises);
await Promise.all(promises);
// Set wasResolved to true
relation.wasResolved = true;
return true;
}
这对this.elementsInView[index].parent = relation;
有什么影响?由于这种突变,我现在关心的是,以parseItem
传递给parseItem
的多个项目是否以交错方式运行可能同时修改它们所依赖的数据
至少就原始问题而言,这种方法应该可以帮助您等待所有承诺的完成。