Rxjs `CombineTest`、`switchMap`和保留内部订阅

Rxjs `CombineTest`、`switchMap`和保留内部订阅,rxjs,observable,Rxjs,Observable,我有一个可观察到的)。给定代码: import 'rxjs/Rx'; import { Observable } from 'rxjs'; const debugObservable = <T>(t$: Observable<T>, name: string) => new Observable<T>(observer => { console.log(name, 'subscribe'); const s

我有一个
可观察到的)。给定代码:

import 'rxjs/Rx';
import { Observable } from 'rxjs';

const debugObservable = <T>(t$: Observable<T>, name: string) =>
    new Observable<T>(observer => {
        console.log(name, 'subscribe');
        const subscription = t$.subscribe(observer);
        return () => {
            console.log(name, 'unsubscribe');
            return subscription.unsubscribe();
        };
    });

const ofSingle = <T>(t: T) =>
    new Observable<T>(observer => {
        observer.next(t);
    });

const observableOfArrayOfObservablesOfNumber = new Observable<
    Array<Observable<number>>
>(observe => {
    const keep = debugObservable(ofSingle(1), 'keep');
    const remove = debugObservable(ofSingle(2), 'remove');
    const add = debugObservable(ofSingle(3), 'add');

    observe.next([keep, remove]);

    setTimeout(() => {
        observe.next([keep, add]);
    }, 2000);

    return () => {};
});

// The `switchMap` will unsubscribe to the previous inner observable *before* subscribing to the new
// inner observable.
const final$ = observableOfArrayOfObservablesOfNumber.switchMap(
    arrayOfObservablesOfNumber => {
        const observableOfArrayOfNumbers = Observable.combineLatest(
            arrayOfObservablesOfNumber,
        );
        return debugObservable(
            observableOfArrayOfNumbers,
            'observableOfArrayOfNumbers',
        );
    },
);

final$.subscribe(x => console.log('final', x));

最接近您描述的是Cycle.js Ononify中调用的xstream操作符

似乎没有一个正式的RxJS操作符可以解决这个问题,但是可以构建自己的操作符来实现这个行为。您可以使用pickCombine的xstream实现作为参考

主要部分包括:

  • 流在以前版本中不存在,但在新版本中存在:
  • 流存在于以前的中,但不存在于新的中:

请注意,创建一个数组(使用映射并依靠键消除数组项的歧义)比直接在数组上创建更容易、更高效。您可以对外部API隐藏自定义数据结构。

我最终实现了这一点,方法是使用publishReplay(1)
发布并重放内部观察值,然后进行ref计数

请注意,
refCount
是不够的,因为当
switchMap
取消订阅以前的内部可观察对象(在订阅新的内部可观察对象之前)时,计数将下降到
0
,因此我不得不使用一个特殊的
refCountWithDelay
操作符,它只在延迟后通过ref计数取消订阅(即,在事件循环的同一滴答声内,但不同步)。更多信息如下:

  • refCountWithDelay


请注意,
keep
只订阅了一次。

我想出了一个更好的解决方案,使用
rxjs等的
combineLatestHigherOrder


您可以使用自定义运算符来实现这一点-类似于
combinelatetest
的功能,但可以像您描述的那样交换可观测值和发出值。您可以使用自定义运算符还是坚持现有运算符的组合?自定义很好!这看起来很有希望,尽管我有点坚持将其作为RxJS实现接线员…
observableOfArrayOfNumbers subscribe
keep subscribe
remove subscribe
final [1, 2]
keep unsubscribe <--- bad!
remove unsubscribe
observableOfArrayOfNumbers unsubscribe
observableOfArrayOfNumbers subscribe
keep subscribe <--- bad!
add subscribe
final [1, 3]
observableOfArrayOfNumbers subscribe
keep subscribe
remove subscribe
final [1, 2]
remove unsubscribe
observableOfArrayOfNumbers unsubscribe
observableOfArrayOfNumbers subscribe
add subscribe
final [1, 3]
const createObservable = <T>(t: T, name: string) => {
  return refCountWithDelay(debugObservable(ofSingle(t), name).publishReplay(1), 0, 0);
}

const observableOfArrayOfObservablesOfNumber = new Observable<
    Array<Observable<number>>
>(observe => {
    const keep = createObservable(1, 'keep');
    const remove = createObservable(2, 'remove');
    const add = createObservable(3, 'add');

    observe.next([keep, remove]);

    setTimeout(() => {
        observe.next([keep, add]);
    }, 2000);

    return () => {};
});
observableOfArrayOfNumbers subscribe
keep subscribe
remove subscribe
final [1, 2]
observableOfArrayOfNumbers unsubscribe
observableOfArrayOfNumbers subscribe
remove unsubscribe
add subscribe
final [1, 3]