Итак, я немного поиграл, выполнил некоторую ручную рекурсию (вместо того, чтобы полагаться на expand
) и придумал следующее (также обновленное по ссылке на stackblitz выше):
class Test {
// This doesn't maintain depth-first order; it can vary depending on timing.
brokenDFS(getChildren: Getter, ids: number[]): Observable<number[]> {
return of(ids).pipe(
concatMap(ids => from(ids)),
expand(id => getChildren(id)),
toArray()
);
}
workingDFS(getChildren: Getter, ids: number[]): Observable<number[]> {
return from(ids).pipe(
concatMap(id => this.parentAndChildren(getChildren, id)),
toArray()
);
}
private parentAndChildren(getChildren: Getter, id: number): Observable<number> {
return of(id).pipe(
concat(
getChildren(id).pipe(
map(child => this.parentAndChildren(getChildren, child)),
concatAll()
)
),
);
}
}
const getter = getChildrenWithDelay;
const rootIds = [1, 17, 20];
const test = new Test();
test.brokenDFS(getter, rootIds).subscribe(data => console.log(`Broken: ${data}`));
test.workingDFS(getter, rootIds).subscribe(data => console.log(`Working: ${data}`));
Вывод (с учетом того, что «сломанный» вывод может изменяться из-за синхронизации):
Broken: 1,17,20,21,2,6,18,7,13,14,3,4,19,15,16,5,8,9,10,11,12
Working: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21
(Также обратите внимание, что я изменил значения дерева из исходного поста, так что правильный DFS - это числовой массив от 1 до 21).
Так что workingDFS
работает, но намного медленнее, чем brokenDFS
, так как каждый запрос к http-серверу должен ждать, пока все завершится, в то время как версия brokenDFS
будет запускать несколько запросов одновременно (хотя это не правильно порядок).
Я не знаю, есть ли у меня лучшие варианты rxjs здесь. Возможно, мне придется пересмотреть свои методы, чтобы передать не только интересующие объекты, но также некоторую информацию о структурировании / сортировке, выполнить все / многие запросы одновременно, а затем объединить все в правильном порядке.