Правильный способ фильтрации двух наблюдаемых

#angular #rxjs #observable

#angular #rxjs #наблюдаемый

Вопрос:

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

 get availableCodeValueLanguages$(): Observable<Common.Lookup<string>[]> {
    return this.languageCodesLookupData$.pipe(
      withLatestFrom(this.languageData$),
      map(([lookupLanguages, codeValues]) => {
        const codeValueLanguageCodes = codeValues.map(codeValue => codeValue.language.id);
        return lookupLanguages.filter(lookupLanguage =>
          !codeValueLanguageCodes.includes(lookupLanguage.id));
      }),
      catchError(error => {
        return of([]);
      })
    )
  }
  

languageData $ содержит данные для сетки. Это список сложных свойств CodeValue, каждое из которых включает в себя отдельный язык. languageCodesLookupData$ — это полный список всех доступных языков. availableCodeValueLanguages $ должен включать языки для выпадающего списка, должна быть возможность добавлять только один язык для каждого значения кода в форме.

languageCodesLookupData $ загружается при инициализации компонента (маловероятно, что это изменится во время работы со страницей). Соответственно, languageData $ изменяется, как только мы добавляем новую запись в список CodeValue в форме.

Комментарии:

1. Выглядит нормально, вы также можете использовать combileLatest operator для достижения этой цели.

2. Вам не нужно использовать get , вы можете просто определить как availableCodeValueLanguages$ = this.languageCodesLookupData$.pipe(...)

3. @bizzybob — это лучше с точки зрения производительности или просто короче? 🙂

4. просто короче… нет преимущества в производительности:-(

Ответ №1:

Ваш код выглядит нормально с точки зрения производительности, использование withLatestFrom является типичным способом объединения потоков.

Однако…

languageCodesLookupData $ загружается при инициализации компонента (маловероятно, что это изменится во время работы со страницей)

Использование withLatestFrom будет выдавать только тогда, когда исходная наблюдаемая выдает.

languageData $ изменяется, как только мы добавляем новую запись в список CodeValue в форме.

Итак, я предполагаю, что вы хотели бы availableCodeValueLanguages$ , когда это произойдет. Если это так, вам следует использовать combineLatest :

 availableCodeValueLanguages$ = combineLatest(
  this.languageCodesLookupData$,
  this.languageData$
).pipe(
  map(([lookupLanguages, codeValues]) => {
    const codeValueLanguageCodes = codeValues.map(codeValue => codeValue.language.id);
    return lookupLanguages.filter(lookupLanguage =>
      !codeValueLanguageCodes.includes(lookupLanguage.id));
  }),
  catchError(error => {
    return of([]);
  })
);
  

Вы могли бы определить codeValueLanguageCodes как свою собственную наблюдаемую, если хотите.

 codeIds$ = this.languageData$.pipe(
    map(codeValue => codeValue.language.id)
);

availableCodeValueLanguages$ = combineLatest(
  this.languageCodesLookupData$,
  this.codeIds$
).pipe(
  map(([languages, codeIds]) => languages.filter(
    language => !codeIds.includes(language.id));
  ),
  catchError(error => {
    return of([]);
  })
);
  

Комментарии:

1. У меня есть другая реализация по-другому, с использованием моего пользовательского export class ExcludeIdsFilterPipe implements PipeTransform (его код прост и не показан для храбрости), например: licencesLookupData$ | async | excludeIdsFilter: { excludeIds: nonAvailableModuleLicenceIds, isNumeric: true } и excludeIds выводится как this.store.select(state => state.ModuleLicencesState).pipe(takeUntil(this.destroy)).subscribe((state: ModuleLicences.State) в конструкторе компонентов. Не могли бы вы сказать, все ли в порядке?

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