Ожидание выполнения внутренних обещаний

#typescript #promise

#typescript #обещание

Вопрос:

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

Поэтому я использую этот Promise.allSettled метод. Это работает, если два обещания являются плоскими. Но если одно из этих обещаний состоит из внутренних обещаний, это не сработает.

  Promise.allSettled([
  report?.getActivePage(), //return a Promise object
  exportVisualData("9df20366a984c945beb5")
 ])
  .then((results) => {
    results.forEach((result, index) => {
      if (result.status === "rejected") {
        const rejectedResult: PromiseRejectedResult =
          result as PromiseRejectedResult;
        console.log(rejectedResult);
      } else if (result.status === "fulfilled") {
        if (index === 0) {
          const fulfilledResult: PromiseFulfilledResult<Page | undefined> =
            result as PromiseFulfilledResult<Page | undefined>;
          console.log(fulfilledResult);
          fulfilledResult.value?.setActive();
        } else {
          const fulfilledResult: PromiseFulfilledResult<void | IExportDataResult> =
            result as PromiseFulfilledResult<void | IExportDataResult>;
          console.log(fulfilledResult);
        }
      }
   });

function exportVisualData(id: string): Promise<void | IExportDataResult> {
return report!.getPages().then((pages) => {
  pages.forEach((page) => {
    page.getVisuals().then((visualDescriptors) =>
      visualDescriptors.forEach((visualDescriptor) => {
        if (visualDescriptor.name === id) {
          if (!page.isActive) {
            page.setActive().then((__) => {
              return visualDescriptor?.exportData(
                ExportDataType.Summarized
              );
            });
          } else {
            return visualDescriptor?.exportData(ExportDataType.Summarized);
          }
        }
      })
    );
  });
});
 

Promise.allSettled не имеет результата во втором из-за внутренних обещаний, как я могу заставить это работать.

{статус: ‘выполнено’, значение: Страница} {статус: ‘выполнено’, значение: не определено}

Комментарии:

1. Я не следую вашему коду, но внутренние обещания могут отслеживаться только внешним / содержащим обещанием, если вы return их извлекаете из .then() обработчика, чтобы они были связаны вместе. И вы также не можете сделать это должным образом из .forEach() цикла, потому что возврат чего-либо из .forEach() цикла никуда не приведет. Вероятно, вместо этого вам нужно будет перейти к for циклу. И, если вам нужно отслеживать все обещания в цикле, затем используйте Promise.all() или Promise.allSettled() там.

2. @jfriend00 не могли бы вы, пожалуйста, написать пример с псевдокодом, я думаю, что я не могу следовать за вами на 100 процентов

3. Я пытался переписать вашу exportVisualData() функцию, но я не могу сказать, что вы собираетесь делать, когда делаете return visualDescriptor?.exportData(ExportDataType.Summarized); . К чему вы пытаетесь это вернуть? Вы находитесь внутри цикла, поэтому пытаетесь ли вы выйти из цикла, когда переходите к этому оператору, или вы пытаетесь накапливать результаты каждой итерации цикла? Я не понимаю, что должен делать этот код. Куда это возвращаемое значение должно идти? Куда N из них должны идти?

4. visualDescriptor?.exportData(ExportDataType.Summarized) это метод из API Power BI (игровая площадка. powerbi.com/de-de/dev-sandbox ). В настоящее время моя цель — экспортировать данные только для одного примера visual. В конце я хочу собрать данные из разных визуальных объектов внутри одного вызова функции как часть массива. Поэтому я должен изменить ввод со строки на массив строк.

5. Хорошо, итак, вам нужен плоский массив результатов с любым количеством совпадений?

Ответ №1:

Вот переписанная exportVisualData() функция, которая собирает все результаты, соответствующие вашему visualDescriptor.name тесту, в массив и превращает этот массив в разрешенное значение exportVisualData() возвращаемого обещания.

Я не знал visualDescriptor?.exportData(ExportDataType.Summarized) , возвращает ли обещание или нет. В случае, если это произойдет, я ставлю await перед ним. Если он просто возвращает значение напрямую, вы можете удалить это await .

Кроме того, я не знаю TypeScript, поэтому вам придется добавить информацию о типе в этот код:

 async function exportVisualData(id: string): Promise < void | IExportDataResult > {
    const results = [];
    const pages = await report!.getPages();
    for (let page of pages) {
        let visualDescriptors = await page.getVisuals();
        for (let visualDescriptor of visualDescriptors) {
            if (visualDescriptor.name === id) {
                if (!page.isActive) {
                    await page.setActive();
                }
                results.push(await visualDescriptor?.exportData(ExportDataType.Summarized));
            }
        }
    }
    return results;
}
 

Обратите внимание, что при этом не выполняются все эти асинхронные операции параллельно, поэтому нет необходимости использовать Promise.allSettled() результат. Он просто возвращает одно обещание, которое преобразуется в массив значений.

Если вы хотите перехватывать ошибки и продолжать обработку в этой функции, вы можете попробовать / перехватить в каждом цикле и continue в catch .

Если вы хотите запускать все параллельно, это сложнее кодировать здесь из if (visualDescriptor.name === id) -за того, что вы хотите пропустить некоторые элементы, чтобы вы не знали, сколько результатов вы ожидаете, пока не дойдете до результатов.