Вызов метода для объекта массива и дочерних элементов в ReactiveX - PullRequest
0 голосов
/ 05 февраля 2019

Я хочу создать наблюдаемое из дерева.Каждый узел будет генерировать наблюдаемую, которая зависит от наблюдаемой его родителя (например, через switchMap).На каждом уровне дерева необходимо объединить наблюдаемые для каждого потомка.

Я хочу преобразовать этот код так, чтобы он использовал наблюдаемые:

interface Request {
    name: string;
    childrens?: Request[];
}

start() {
  this.nextRequests(this.requests);
}

private nextRequests(requests: Requests[]) {
  requests.forEach(request => {
    this.socketService.message(request.name, (res) => {
      if (request.childrens) {
        this.nextRequests(request.childrens, res);
      }
    });
  });
}

Так вот, что я думалэто будет выглядеть так:

interface Request {
    name: string;
    childrens?: Request[];
}

// This isn't right. 
// SocketService.message return a observable, the reponse of the request.
start(requests: Request[]): Observable<any> {
  return from(requests).pipe(switchMap(request => {
      return this.socketService.message(request.name);
    }), concatMap(request => {
    if (request.childrens) {
      return this.start(request.childrens);
    }
    return of(request.name);
  }));
}

const mock: Request[] = [
    {name: 'test1', childrens: [
        { name: 'test4' },
        { name: 'test5' }
    ]},
    { name: 'test2' },
    { name: 'test3' }
];

this.start(mock).subscribe((name) => {
    console.log(`Request ${name} done`);
}, err => { }, () => {
    console.log('Complete');
});


И вывод будет выглядеть так:

Request test1 done
Request test2 done
Request test3 done
Request test4 done
Request test5 done

Complete

Но вместо этого я получаю это:

Request test2 done
Request test3 done
Request test4 done
Request test5 done

Порядокэмиссия между узлами братьев и сестер не важна.Но родители с детьми не печатаются (test1), и полный обратный вызов никогда не выполняется.Почему это так?

Спасибо!

1 Ответ

0 голосов
/ 05 февраля 2019

Основная проблема здесь в том, что вы не добавляете элемент test1 в качестве параметра к

if (request.childrens) {
  return this.start(request.childrens);
}

Он должен выглядеть как

if (request.childrens) {
  return this.start([{name:request.name},...request.childrens]);
}

Таким образом вы получитеtest1 в подписке как первое значение, иначе оно никогда не будет зарегистрировано, потому что оно будет отфильтровано потоком.

РЕДАКТИРОВАТЬ:

Теперь есть также демонстрация BFS-ishв ссылке ниже

код выглядит так

function startBFS(requests) {
  return merge(from(requests)).pipe(
    mergeMap((x, i) => {
      if (x.children) {
        return concat(of(x), startBFS(x.children));
      } else {
        return of(x);
      }
    })
  );
}

Вот демоверсия codeSandbox

...