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]