#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. Я думаю, что производительность может быть хорошей при этом. Я бы предпочел поместить логику в контроллер вместо канала. Каналы хороши тем, что они могут выполнять логику чистым способом, который вы можете легко прочитать в своем шаблоне. Но если вам нужно передать объекты в канал, это становится беспорядочным и теряет читаемость. Итак, я думаю, что проще выполнить логику преобразования в вашем наблюдаемом потоке в контроллере.