首页 > 解决方案 > 如何在 rxjs 中的“输出设备”之间切换事件流

问题描述

我有一个 rxjs 主题是 WebMidi 笔记流(一个笔记是一个数字数组),另一个主题是选定的 midi 输出设备流:

const midiOutputDeviceSubject$ = new Subject<WebMidi.MIDIOutput>();
const midiNoteStream$ = new Subject<number[]>();

我想将新设备发送到 midiOutputDeviceSubject$ 流,以便发送到 midiNoteStream$ 的所有后续笔记都转到该新设备。我试过这个:

midiOutputDeviceSubject$.subscribe(outputDevice => {
    midiNoteStream$.subscribe(s => 
        outputDevice.send(s));
    }
});

当有新设备时,它会向笔记流添加新订阅,但不会删除旧设备。我认为有一个使用 switchMap 的简单解决方案,但我就是看不到它。

标签: rxjs

解决方案


这(或接近的东西)应该可以工作。

const midiOutputDeviceSubject$ = new Subject<WebMidi.MIDIOutput>();
const midiNoteStream$ = new Subject<number[]>();

midiOutputDeviceSubject$.pipe(
  switchMap(outputDevice => midiNoteStream$.pipe(
    tap(s => outputDevice.send(s))
  ))
).subscribe();

虽然更惯用的解决方案可能是:

const midiOutputDeviceSubject$ = new Subject<WebMidi.MIDIOutput>();
const midiNoteStream$ = new Subject<number[]>();

midiNoteStream$.pipe(
  withLatestFrom(midiOutputDeviceSubject$)
).subscribe(([s, outputDevice]) => 
  outputDevice.send(s);
);

因为这会使您的副作用包含在其中subscribe而不是污染流。它也不会为取消订阅和重新订阅同一个流(midiNoteStream$)而烦恼。它只是维护这两个订阅。

但实际上,它更容易理解和维护。


推荐阅读