Как создать наблюдаемый объект, который пропускает выбросы между 2 событиями

#javascript #rxjs #rxjs-observables

#javascript #rxjs #rxjs-наблюдаемые

Вопрос:

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

У меня есть эти потоки:

 pedalDown$
pedalUp$
keyUp$
 

Как я могу объединить их вместе в наблюдаемый объект, который выдает события только тогда, когда педаль не нажата? unsustainedUp$ keyUp$

Я думал, что это может сработать, но unsustainedUp$ срабатывает даже тогда, когда keyUp$ после a pedalDown$ и перед a pedalUp$ .

 unsustainedUp$ = keyUp$.pipe(
    skipUntil(pedalUp$),
    takeUntil(pedalDown$),
    repeat()
)

// once at setup, fire into pedal-up to get this into the correct, normal piano initial state
pedalUp$.next()
 

Ответ №1:

Я думаю, вы могли бы сделать это так. Возможно, вам понадобится startWith() в зависимости от pedalUp$ функциональности.
Кстати, are pedalDown$ и другие Subjects , BehaviorSubjects или ReplaySubjects ?:

 pedalUp$.pipe(
  switchMap(() => keyUp$.pipe(
    takeUntil(pedalDown$),
  )),
 

Живая демонстрация: https://stackblitz.com/edit/rxjs-v2wkhq ?devtoolsheight=60

Я попробовал также ваше решение, потому что мне кажется, что оно должно работать так же хорошо, и оно работает:

https://stackblitz.com/edit/rxjs-ngorgw?devtoolsheight=60

Поэтому убедитесь, что исходные наблюдаемые объекты излучают, потому что это может быть проблемой.

Ответ №2:

Настройка ваших потоков делает это несколько сложнее. Один из способов сделать это — закодировать, включена ли педаль в данный момент в свой собственный поток, который выдает true, когда педаль включена, и false, когда она выключена. Здесь я по умолчанию true (педаль запускается).

Затем мы можем объединить их, отфильтровать все значения при нажатой педали, а затем выдать keyUp$ значения при необходимости.

вот так:

 const isPedalUp$ = merge(
  pedalUp$.pipe(mapTo(true)),
  pedalDown$.pipe(mapTo(false))
).pipe(
  startWith(true)
);

unsustainedUp$ = keyUp$.pipe(
  withLatestFrom(isPedalUp$),
  filter(([_,isUp]) => isUp),
  map(([kepUp,_]) => kepUp)
);
 

Другой подход заключается в переключении в и из keyUp$ . Вам потребуется многоадресная keyUp$ рассылка, если это еще не сделано.

 unsustainedUp$ = merge(
  pedalUp$.pipe(mapTo(true)),
  pedalDown$.pipe(mapTo(false))
).pipe(
  startWith(true),
  switchMap(isUp => isUp ?
    keyUp$,
    EMPTY
  )
);