Рекурсивно создавать новые обещания - PullRequest
0 голосов
/ 23 мая 2018

Я пытаюсь заставить функцию Promise.all работать с рекурсивной структурой.

Функция, которая была вызвана из цикла for, также может создавать обещания, но каким-то образом функция 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 );
        }
    }
}

1 Ответ

0 голосов
/ 23 мая 2018

Проблема возникает из-за того, что вы пытаетесь поделиться this.promised между update() и асинхронным поведением внутри parseItem().

. Чтобы исправить это, вы можете вместо этого вернуть Promise из 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 на update, которые выполняются в режиме чередования, одновременно изменять данные, от которых они зависят.

По крайней мере, с точки зрения исходного вопроса, этот метод должен помочь вам дождаться выполнения всех обещаний.

...