#rxjs #rxjs6
#rxjs #rxjs6
Вопрос:
У нас есть служба запросов, которая выполняет http-запросы. Все запросы реализуют интерфейс IRequest, который содержит http-метод и функцию execute, которая, в свою очередь, возвращает другое наблюдаемое значение.
RequestService имеет перегрузку, которая принимает исходное наблюдаемое и requestfactory, который возвращает экземпляр IRequest на основе значения исходного наблюдаемого.
export interface IRequest<TResponse> {
__method: string;
execute(): Observable<TResponse>;
}
class RequestService<TSource, TResponse> {
public execute(source: Observable<TSource>, requestFactory: (input: TSource) => IRequest<TResponse>): Observable<TResponse> {
return source.pipe(
map(x => requestFactory(x)),
switchMap(x => x.execute()),
);
}
}
Конечно, в службе выполняется намного больше (ведение журнала, обработка ошибок по умолчанию, …), но большая часть не имеет отношения к вопросу.
Теперь все это работает как по волшебству, но то, что мы хотели бы сделать, это использовать switchMap
для GET-запросов и ‘mergeMap’ для запросов POST, PUT, DELETE по умолчанию.
Похоже, мы не можем заставить это работать. Нам нужен доступ к экземпляру IRequest после того, как он был создан фабрикой, что возможно только в том случае, если у нас есть исходное наблюдаемое значение. Однако при использовании оператора мы больше не можем контролировать выбор между switchMap или mergeMap.
Нашим следующим выбором было создать наш собственный, RequestMapOperator
который создавал бы экземпляр MergeMapOperator
or SwitchMapOperator
и использовал соответствующие методы next, complete и error. Однако SwitchMapOperator
не экспортируется библиотекой rxjs.
Итак, прежде чем создавать наш собственный класс Subscriber, который был бы просто комбинацией MergeMapSubscriber
и SwitchMapSubscriber
, мы хотели бы знать, не упускаем ли мы чего-то.
TL; DR
Нам нужен оператор, который, в зависимости от значения исходной наблюдаемой, преобразуется в новую наблюдаемую с помощью mergeMap или switchMap.
Комментарии:
1. С этой проблемой я столкнулся. Мы прибегли к написанию нашего собственного,
RequestMapOperator
но столкнулись с некоторыми проблемами (переключение между различными реализациями_next
и условиями гонки) Если вы нашли решение, пожалуйста, поделитесь им! Спасибо!2. Все еще надеясь, что кто-нибудь придумает ответ 🙂 На данный момент мы тоже прибегли к написанию нашего собственного
RequestMapOperator
и Subscriber путем сравнения и объединения источника из операторов mergeMap и switchMap. В нашем случае мы предполагаем, что для одного и того же наблюдаемого источника (запроса) выбор между переключением и функциональностью слияния никогда не меняется, потому что метод запроса никогда не меняется. Если это произойдет, мы выдадим ошибку (в_next
методе, подобном тому, который вы упомянули), чего на самом деле, вероятно, никогда не будет.
Ответ №1:
Вы могли бы использовать функцию RXJS iif, которая принимает функцию условия в качестве первого параметра и на основе возвращаемого значения решает, на какую наблюдаемую подписаться.
Например.
class RequestService<TSource, TResponse> {
public execute(source: Observable<TSource>, requestFactory: (input: TSource) => IRequest<TResponse>): Observable<TResponse> {
return source.pipe(
map(x => requestFactory(x)),
// using mergemap outside because we don't want to cancel inner
// observable
margeMap((x) =>
iif(() => x.method === "GET",
switchMap(x => x.execute()),
margeMap(x => x.execute())
)
)
);
}
}
Надеюсь, это поможет.
Комментарии:
1. Это именно то, что я попробовал сначала, но
iif
оператор ожидает, что observable (ну, subscribable, чтобы быть правильным) в качестве второго и третьего параметров. ОбаswitchMap
иmergeMap
имеют типOperatorFunction
. Хотя спасибо за предложение.