Есть ли способ ждать результата наблюдаемой, вызываемой внутри другой наблюдаемой? - PullRequest
1 голос
/ 04 июля 2019

В настоящее время я экспериментирую с созданием небольшого приложения для моей местной группы по ролевой игре. Среди инструментов, которые они хотели, был рандомизатор с возможностью написания сценариев, чтобы они могли создавать таблицы бросков кубиков. К сожалению, я натолкнулся на небольшую кирпичную стену о необходимости рекурсивного вызова функции с наблюдаемой в ней.

Я просмотрел несколько различных вопросов здесь и в Reddit, в которых рассказывается, как получить результаты из Observables или ждать, пока она не будет решена, но все решения, которые я пробовал, либо являются неверным кодом в этом контексте, либо родительским вызовом. не ждет, пока ребенок решит Это включает в себя использование map, switchMap и async / await. У меня возникает вопрос, не ошибаюсь ли я, используя Observable для загрузки файла на этом.

Вот полный контекст на случай, если короткий пример пропустит что-то: https://github.com/Acaeris/draconika/blob/rolltable/src/app/providers/table.service.ts

Короче говоря:

@Injectable()
export class TableService {
  constructor(private http: HttpClient) {}

  get(tableId: string): Observable<RollCollection> {
    return this.http.get<RollCollection>('assets/tables/' + tableId + '.json')
      .pipe(
        catchError(this.handleError)
      );
  }

  // Roll a result from a given table or sub entry.
  roll(tableId: string, entryKey: string) {
    return this.get(tableId).pipe(
      map(data => {
        output = data[entryKey];
        parts = this.findParts(output);

        parts.forEach((part: string) => {
          if (part[1].includes('.')) {
            const splitPart = part[1].split('.');

            // Roll refers to an entry in another table.
            // This needs to finish before the return...
            this.roll(splitPart[0], splitPart[1]).toPromise()
              .then(rollOutput => output = output.replace(part[0], rollOutput));

          } else {
            // Process rolls for current file.
          }
        });

        return output;
      }
    );
  }

  private findParts(entry: string) {
    const regex = /\[([a-zA-Z.]*)\]/g;
    const parts: string[] = [];
    let m;

    do {
      m = regex.exec(entry);

      if (m) {
        parts.push(m);
      }
    } while (m);

    return parts;
  }
}

В настоящее время он вызывается в компоненте следующим образом:

this.tableService.roll('heirloom').subscribe(
  data => this.output.push(data),
  error => console.log(error)
);

В таблице heirloom.json есть некоторые броски, которые приводят к вызовам [name.format], которые затем должны свернуть запись 'format' файла name.json.

То, что я ожидаю от него, это бросить результат и заменить часть [name.format] строки из рулона семейной реликвии.

this.tableService.roll('name', 'format').subscribe(
  data => this.output.push(data),
  error => console.log(error)
);

^ Это успешно вернет сгенерированное имя, и действительно, внутренний бросок также приведет к имени, но оно применяется слишком поздно для вывода, и поэтому компонент получает результат до его завершения.

В настоящее время я получаю следующее: «Семейная реликвия - это шлем, который когда-то принадлежал [name.format]» вместо «Семейная реликвия - это шлем, который когда-то принадлежал Леди Амберлайн Зари»:

...