Javascript 在Rxjs中,如何展平或合并包含正常类型和可观察对象的流?

Javascript 在Rxjs中,如何展平或合并包含正常类型和可观察对象的流?,javascript,rxjs,reactivex,Javascript,Rxjs,Reactivex,与数组类似,展平([1,2[3,4],[5,6]])===[1,2,3,4,5,6] 我想在rxjs可观测中做到这一点: const test$ = Rx.Observable.from( [1, 2, Rx.Observable.from([3, 4]), 5, Rx.Observable.from([6, 7])] ).mergeAll() test$.subscribe(x => console.log(x)) //I want to output 1, 2, 3, 4,

与数组类似,
展平([1,2[3,4],[5,6]])===[1,2,3,4,5,6]

我想在rxjs可观测中做到这一点:

const test$ = Rx.Observable.from(
    [1, 2, Rx.Observable.from([3, 4]), 5, Rx.Observable.from([6, 7])]
).mergeAll()

test$.subscribe(x => console.log(x)) //I want to output 1, 2, 3, 4, 5, 6, 7
mergeAll不工作并抛出错误

下面是一个非常肮脏的解决方案:

const inElegant$ = Rx.Observable.merge(
  test$.filter(x => x instanceof Rx.Observable).mergeAll(),
  test$.filter(x => !(x instanceof Rx.Observable))
)

inElegant$.subscribe(x => console.log(x));
有没有更好的解决办法

Jsbin

根据
mergeAll

将可观测序列的可观测序列合并为可观测序列

你有一个混合的集合(数字和可观测值),所以不起作用


唯一的方法是如何处理,用不同的方法处理这两种类型:尽管你应该问问自己,为什么在同一序列中同时有可观察类型和基本类型。

我个人使用
toObservable
转换函数来处理这些情况。该函数保持observable不变,并将其他类型封装在observable中(使用
Rx.obbservable.return
)。所以它是这样使用的:

const test$ = Rx.Observable.from(
    [1, 2, Rx.Observable.from([3, 4]), 5, Rx.Observable.from([6, 7])]
).map(toObservable).mergeAll()

这与您正在做的非常接近,但我发现将其打包到一个单独的函数中非常方便,可以在其他上下文中重用

如果表单上有流

const stream = Rx.Observable.from(
    [1, 2, Rx.Observable.from([3, 4]), 5, Rx.Observable.from([6, 7]), 8])
有几种方法可以将其转换为纯数字流(不包括解决方案中的过滤)

以下是三种可能的解决方案:

// prints 1, 2, 3, 4, 5, 6, 7
stream
    .select(e => typeof e == 'number' ? Rx.Observable.from([e]) : e)
    .concatAll()
    .subscribe(x => console.log(x));

// prints 1, 2, 3, 4, 5, 6, 7
stream
    .selectMany(e => typeof e == 'number' ? Rx.Observable.from([e]) : e)
    .subscribe(x => console.log(x));

// prints 1, 2, 3, 4, 5, 6, 7
stream
    .select(e => typeof e == 'number' ? Rx.Observable.from([e]) : e)
    .mergeAll()
    .subscribe(x => console.log(x));
这一切看起来都很好。然而,有一些事情要考虑。如果我们更改源流使其异步:

const asyncStream = Rx.Observable.interval(1000)
    .select((val, idx) => idx + 8).take(5);

const stream = Rx.Observable.from(
    [1, 2, Rx.Observable.from([3, 4]), 5, Rx.Observable.from([6, 7]),
    asyncStream, 13, 14, 15])
我们使用与前面相同的解决方案得到以下结果:

// prints 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
stream
    .select(e => typeof e == 'number' ? Rx.Observable.from([e]) : e)
    .concatAll()
    .subscribe(x => console.log(x));

// prints 1, 2, 3, 4, 5, 6, 7, 13, 14, 15, 8, 9, 10, 11, 12
stream
    .selectMany(e => typeof e == 'number' ? Rx.Observable.from([e]) : e)
    .subscribe(x => console.log(x));

// prints 1, 2, 3, 4, 5, 6, 7, 13, 14, 15, 8, 9, 10, 11, 12
stream
    .select(e => typeof e == 'number' ? Rx.Observable.from([e]) : e)
    .mergeAll()
    .subscribe(x => console.log(x));
总而言之。使用
selectMany
select
然后再使用
mergeAll
可以解决生成正确类型的扁平列表的问题,但不会保持顺序。这些解决方案将侦听所有流,并在任何流产生值时产生结果

concatAll
解决方案的行为稍有不同。此解决方案将按顺序侦听每个流,仅当最后一个流完成时才切换到下一个值/流


所以这些是一些解决方案,你想要哪一个取决于你的需要。但是,它们都不再需要过滤流。

请为
转换函数添加代码?