В настоящее время я экспериментирую с созданием небольшого приложения для моей местной группы по ролевой игре. Среди инструментов, которые они хотели, был рандомизатор с возможностью написания сценариев, чтобы они могли создавать таблицы бросков кубиков. К сожалению, я натолкнулся на небольшую кирпичную стену о необходимости рекурсивного вызова функции с наблюдаемой в ней.
Я просмотрел несколько различных вопросов здесь и в 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]» вместо «Семейная реликвия - это шлем, который когда-то принадлежал Леди Амберлайн Зари»: