Преобразование массива наблюдаемых в массив

1

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

Моя модель выглядит следующим образом:

export interface MyModel {
    itemOne: Observable<ItemOne[]>;
    itemTwo: Observable<ItemTwo[]>;
    itemThree: Observable<ItemThree[]>;
}

Мой forkJoin выглядит так:

this._subscriptions.push(this.myService.getData()
    .flatMap(data => Observable.forkJoin(data
        .map(data => {
            let myModel: MyModel = {
                itemOne: this.myService.getSomeData(),
                itemTwo: this.myService.getSomeData(),
                itemThree: this.myService.getSomeData()
            };
            return Observable.forkJoin(Observable.from([myModel]));
}))).subscribe(details => {
    details.map(this.toMyModelViewModel.bind(this));
}));

Теперь, в моем методе toMyModelViewModel, я хотел бы выбрать каждое значение из этих Observables и задавался вопросом, как я мог бы это сделать?

toMyModelViewModel(value: MyModel): any {
    return {
        itemOne: value.itemOne,
        itemTwo: value.itemTwo,
        itemThree: value.itemThree
    };
}

Должен ли я подписаться на каждое значение, чтобы получить текущее значение, или есть другой, возможный лучший/более чистый способ сделать это? В конечном счете, я хотел бы иметь массив объектов MyModel, поэтому мне не нужно беспокоиться об использовании data | async data | async на мой взгляд.

Спасибо

Теги:
angular
rxjs

2 ответа

1

Вы можете преобразовать массив наблюдаемых в наблюдаемый массив, используя любой метод, который вам нравится - тот, который Миллер показывает в своем ответе, будет работать. Мне лично нравится трюк combineLatest (цитируя от redent84 ответ на этот вопрос: как создать наблюдаемый массив из массива наблюдаемых?).

let arrayOfObservables: [Observable<E>] = ...
let wholeSequence: Observable<[E]> = Observable.combineLatest(arrayOfObservables) 

Теперь, для вашего реального вопроса:

Должен ли я подписаться на каждое значение, чтобы получить текущее значение, или есть другой, возможный лучший/более чистый способ сделать это? В конечном счете, я хотел бы иметь массив объектов MyModel, поэтому мне не нужно беспокоиться об использовании данных | async, на мой взгляд.

К сожалению, единственный способ получить Array<any> из Observable<Array<any>> - это подписаться на наблюдаемое и сохранить внутреннее значение в массиве, определенном в другом месте, или (если вы используете Angular как вы), чтобы использовать async трубу.

Вы можете думать об этом так: однажды Observable, всегда Observable. Если значение обернуто в Observable, вы не сможете его получить. Наиболее близким к этому поведению может быть использование BehaviorSubject с методом getValue, но это определенно не вариант для Observables. Это хорошо, потому что это мешает вам использовать асинхронное значение "синхронно" в вашей программе.

Мне также кажется, что я должен упомянуть, что async труба - действительно полезная утилита и должна быть предпочтительной для ручного подписания в целом. Когда вы вручную создаете подписку в своем классе компонентов, вам нужно будет запомнить эту подписку и очистить ее в ngOnDestroy жизненного цикла ngOnDestroy. async трубка великолепна, потому что она выполняет всю эту очистку для вас. Кроме того, вы можете использовать его с безопасным навигационным оператором для обработки значений, которые могут быть неопределенными.

<ul>
  <li *ngFor="let obj of (possiblyUndefined$ | async)?.objects">
    {{ obj.title }}
  </li>
</ul>

Этот код будет намного сложнее, если вы написали все это в своем классе компонента.


Подвести итоги:

1) Вы можете использовать Observable.combineLatest(arrayOfObservables) чтобы подавить ваш массив наблюдаемых в наблюдаемый массив.
2) Вы не можете получить массив "из" наблюдаемого. Вы должны либо подписаться на это наблюдаемое, либо использовать async канал.

1

Из быстрого сканирования вашего кода кажется, что у вас есть начальный api-вызов (this.myService.getData()), из которого вы this.myService.getData() свой результат, но этот результат основан на объединении результатов нескольких вызовов api (this.myService.getSomeData()).

Я чувствую, что вам нужен интерфейс MyModel чтобы не иметь Observables:

export interface MyModel {
    itemOne: ItemOne[];
    itemTwo: ItemTwo[];
    itemThree: ItemThree[];
}

... toMyViewModel - это заводский метод:

function toMyModelViewModel(itemOne: any, itemTwo: any, itemThree: any): MyModel {
    return {
        itemOne: itemOne as ItemOne[],
        itemTwo: itemTwo as ItemTwo[],
        itemThree: itemThree as ItemThree[]
    } as MyModel;
}

... тогда вы будете использовать switchMap/forkJoin следующим образом:

this.myService.getData().switchMap(data => {
  return Observable.forkJoin(
    this.myService.getSomeData(),
    this.myService.getSomeData(),
    this.myService.getSomeData(),
    toMyModelViewModel
}).subscribe(...);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню