Труба RxJS для фильтрации на 2+ ответвления

Предположим, у нас есть субъект, который может возвращать заданный набор значений, для каждого из которых может потребоваться другой подход к ним. Мы могли бы обсудить, должно ли это когда-либо быть, НО это не совсем предмет моего исследования.

Итак ... чтобы справиться с этим, наш код может выглядеть примерно так:

var sub = new Subject(); 

sub.subscribe( 
    data => {
        if (caseA) {
            // do something
        }
        if (caseB) {
            // do something else
        }
     });

что все круто, здорово и все такое ... но мне было интересно, есть ли какой-нибудь оператор, который мы можем связать, чтобы сделать его более rx-ish? Мысль о фильтре, но объединение caseA и caseB просто заставит его не работать (очевидно), поскольку в конечном итоге он отфильтрует оба.

Итак, мой вопрос сводится к следующему: возможно ли иметь что-нибудь отдаленно напоминающее приведенный ниже псевдокод? Какие операторы, которых вы знаете, будут работать таким образом?

var sub = new Subject(); 

sub.pipe(
    magicOperator(//handles caseA),
    magicOperator(//handles caseB),
)
subscribe( 
    data => {
        // handles common thread
     });

person Vlad Pintea    schedule 06.02.2020    source источник
comment
learnrxjs.io/learn-rxjs/operators/transformation/partition   -  person Roberto Zvjerković    schedule 06.02.2020
comment
очень близко, но раздражает то, что вам нужно назвать две константы и подписаться отдельно, но очень очень близко и, вероятно, в конечном итоге вы будете использовать это   -  person Vlad Pintea    schedule 06.02.2020
comment
Вам не нужно создавать переменные. source.pipe(partition(val => val % 2 === 0)).forEach(part => part.subscribe()   -  person Roberto Zvjerković    schedule 06.02.2020
comment
не слишком увлечен этим по сравнению с обычным оператором раздела, но определенно вариант, о котором стоит помнить.   -  person Vlad Pintea    schedule 06.02.2020


Ответы (2)


Я думаю, что более rxjs-способ решения этой проблемы похож на то, что предложил @ritaj, но с использованием статического оператора слияния для секционированных потоков (или concat, если вы хотите обрабатывать их последовательно)

let sub = new Subject();
// i'm using typescript syntax, but you can refer to them by index
let [leftPartition, rightPartition] = sub.pipe( partition( [predicate] ) )
// apply custom logic to the left and right partition
rightPartition = rightPartition.pipe( map( x => x + 1 ) )
leftPartition = leftPartition.pipe( map( x => x - 1 ) )

merge(
     leftPartition,
     rightPartition
).pipe(
    tap( 
        ( value ) => {
            // this stream consumes both right and left partition outputs
        }
    )
).subscribe();

Оператор разделения
Объединить (статический)

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

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

Пс. Обычно я стараюсь, чтобы обратный вызов подписки был свободен от какой-либо реализации, поскольку большая часть того, что вы делаете в конце потока, является побочным эффектом, я помещаю их в оператор касания (те же аргументы, что и у подписки)

person LookForAngular    schedule 06.02.2020
comment
в значительной степени то, что сказал @ritaj, и, вероятно, лучший вариант, который я видел до сих пор. Все еще цепляюсь за надежду, что для всех нас может быть что-то новое, что кто-то скажет, если нет, я отмечу это как ответ через несколько дней - person Vlad Pintea; 06.02.2020

просто создайте объект с функциями для переключения регистра, чтобы сделать код красивее

const handler={
  case1:()=>..handle case1,
  case2:()=>...handle case2
}

sub.map(result=>handler[result])

// experimental switchCase operator 
const switchCase=handlers=>(source)=>source.map(val=>handlers[val]())

// usage
sub.pipe(switchCase({
   case1:....,
   case2:....
}))
person Fan Cheung    schedule 06.02.2020
comment
с точки зрения рефакторинга это, вероятно, хороший способ пойти, если вы не собираетесь использовать оператор раздела (пока), но не на 100% подходящий ответ, поскольку я надеюсь на какое-то решение на основе операторов. Опять же, отличный ответ в целом, и рекомендую всем, кто не использует оператор раздела, но надеется на что-то другое: D - person Vlad Pintea; 06.02.2020
comment
Я думаю, что пользовательский оператор переключения - это то, что нужно. Разделение обрабатывает только true или false, если вам нужно больше гибкости - person Fan Cheung; 06.02.2020
comment
это также совершенно верно, вы можете разделить только на 2 случая - person Vlad Pintea; 06.02.2020
comment
Посмотрим, смогу ли я придумать завтра - person Fan Cheung; 06.02.2020
comment
добавлен простой оператор switchCase, дайте мне знать, работает ли он. - person Fan Cheung; 07.02.2020