【发布时间】:2019-08-07 13:23:24
【问题描述】:
我有一个动态数组结构。具体来说,就是谷歌地图的MVCArray。这个结构有常规的 put、get、remove 方法,以及一个addListener 来监听任何变化。库方法 (Polygon#getPaths) 返回一个 MVCArray of MVCArray of LatLngs,因为多边形可以有任意数量的路径,并且每个路径可以有任意数量的顶点。
我的目标是转换生成一个 PolygonPathEvent 的 Observable,当父 MVCArray 和任何子 MVCArray 发生更改时,它将触发。
创建 Observables
首要任务是将addListener 转换为 Observables。
private createMVCEventObservable<T>(array: MVCArray<T>): Observable<[T[], string, number, T?]>{
const eventNames = ['insert_at', 'remove_at', 'set_at'];
return fromEventPattern(
(handler: Function) => eventNames.map(evName => array.addListener(evName,
(index: number, previous?: LatLng) => this._zone.run(() => handler.apply(array, [[array.getArray(), evName, index, previous]])))),
(handler: Function, evListeners: MapsEventListener[]) => evListeners.forEach(evListener => evListener.remove()));
}
组合 Observables
现在要合并,貌似我们需要使用combineLatest
const pathsChanges$ = this.createMVCEventObservable(paths);
const pathChanges$ = combineLatest(paths.getArray().map(this.createMVCEventObservable));
return combineLatest(pathChanges$, pathsChanges$, (pathArr, paths) =>
new PolygonPathEvent(pathArr, paths);
);
问题是 MVCArray 的父 MVCArray 可以改变,但是 combineLatest 接受一个静态数组。所以当有新路径添加时,我不知道如何让返回的 Observable 也监听这个新路径。同样,如果删除了路径,我不知道如何使返回的 observable 取消订阅已删除的路径。
管道到主题(错误的方法)
我考虑过返回一个主题,并在父 MVCArray<MVCArray<LatLng>> 更改时简单地将其订阅到不同的可观察对象。
const retVal: Subject<PolygonPathEvent> = new Subject();
const pathsChanges$ = this.createMVCEventObservable(paths);
const pathChanges$ = combineLatest(paths.getArray().map(this.createMVCEventObservable));
let latestSubscription = combineLatest(pathChanges$, pathsChanges$, (pathArr, paths) =>
new PolygonPathEvent(pathArr, paths)
).subscribe(retVal);
pathsChanges$.pipe(tap( ([arrays, event, index, previous]) => {
latestSubscription.unsubscribe();
latestSubscription = combineLatest(pathChanges$, pathsChanges$, (pathArr, paths) =>
new PolygonPathEvent(pathArr, paths)
).subscribe(retVal);
} ));
return retVal;
这行得通,问题是订阅原始 Observables(和 addListener)发生在这个方法中,而不是在订阅返回的 Observable 时。
结论
为此我需要某种运算符。
【问题讨论】:
-
你试过
defer运营商吗?您可以订阅其中的更改并返回主题。 -
调查过了,但这不是正确的解决方案。目前正在考虑自定义运算符。