我正在使用rxjs
。
我有一个Browser
,它负责许多Page
个对象。每个页面都有一个Observable<Event>
,可以产生一系列事件。
Page
个对象在不同时间关闭并打开。我想创建一个名为TheOneObservable
的observable,它将合并所有当前活动的Page
对象中的所有事件,并合并来自Browser
对象本身的自定义事件。
关闭Page
意味着应该关闭对它的订阅,这样就不会阻止它进行GC。
我的问题是Pages
可以随时关闭,这意味着合并的Observable的数量总是在变化。我曾考虑使用Pages
的Observable并使用mergeMap
,但这有问题。例如,订阅者只会收到订阅后打开的Pages事件。
请注意,.NET
已对here个问题进行了回答,但使用了ObservableCollection
中未提供的rxjs
。
以下是一些用于说明问题的代码:
class Page {
private _events = new Subject<Event>();
get events(): Observable<Event> {
return this._events.asObservable();
}
}
class Browser {
pages = [] as Page[];
private _ownEvents = new Subject<Event>();
addPage(page : Page) {
this.pages.push(page);
}
removePage(page : Page) {
let ixPage = this.pages.indexOf(page);
if (ixPage < 0) return;
this.pages.splice(ixPage, 1);
}
get oneObservable() {
//this won't work for aforementioned reasons
return Observable.from(this.pages).mergeMap(x => x.events).merge(this._ownEvents);
}
}
它在TypeScript中,但它应该是可以理解的。
答案 0 :(得分:2)
您可以switchMap()
链接到数组的Subject()
更改,在数组更改时将oneObservable替换为新的。
pagesChanged = new Rx.Subject();
addPage(page : Page) {
this.pages.push(page);
this.pagesChanged.next();
}
removePage(page : Page) {
let ixPage = this.pages.indexOf(page);
if (ixPage < 0) return;
this.pages.splice(ixPage, 1);
this.pagesChanged.next();
}
get oneObservable() {
return pagesChanged
.switchMap(changeEvent =>
Observable.from(this.pages).mergeMap(x => x.events).merge(this._ownEvents)
)
}
测试,
const page1 = { events: Rx.Observable.of('page1Event') }
const page2 = { events: Rx.Observable.of('page2Event') }
let pages = [];
const pagesChanged = new Rx.Subject();
const addPage = (page) => {
pages.push(page);
pagesChanged.next();
}
const removePage = (page) => {
let ixPage = pages.indexOf(page);
if (ixPage < 0) return;
pages.splice(ixPage, 1);
pagesChanged.next();
}
const _ownEvents = Rx.Observable.of('ownEvent')
const oneObservable =
pagesChanged
.switchMap(pp =>
Rx.Observable.from(pages)
.mergeMap(x => x.events)
.merge(_ownEvents)
)
oneObservable.subscribe(x => console.log('subscribe', x))
console.log('adding 1')
addPage(page1)
console.log('adding 2')
addPage(page2)
console.log('removing 1')
removePage(page1)
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script>
答案 1 :(得分:0)
您需要自己管理页面订阅,并自行将其事件提供给结果主题:
const theOneObservable$ = new Subject<Event>();
function openPage(page: Page): Subscription {
return page.events$.subscribe(val => this.theOneObservable$.next(val));
}
关闭页面,即在返回的订阅上调用unsubscribe
,已经完成了它必须做的所有事情。
请注意
theOneObservable$
是一个热门观察点。
当然,您可以通过编写自己的可观察类型来更进一步,该类型封装了所有这些API。特别是,这将允许您在关闭时取消订阅所有内部可观察量。
这种方法略有不同:
const observables$ = new Subject<Observable<Event>>();
const theOneObservable$ = observables$.mergeMap(obs$ => obs$);
// Add a page's events; note that takeUntil takes care of the
// unsubscription process here.
observables$.next(page.events$.takeUntil(page.closed$));
这种方法的优越之处在于,当观察者被取消订阅时,它将自动取消订阅内部可观察量。