将动态数组的动态数组转换为 Observable

Convert Dynamic Array of Dynamic Arrays to an Observable

我有一个动态数组结构。具体来说,它是 Google 地图的 MVCArray。这个结构有常规的 put、get、remove 方法,还有一个 addListener 来监听任何变化。库方法 (Polygon#getPaths) returns LatLngs 的 MVCArray 的 MVCArray,因为多边形可以有任意数量的路径,并且每个路径可以有任意数量的顶点。

我的目标是转换生成一个 PolygonPathEvent 的 Observable,当父 MVCArray 或任何子 MVCArray 将被更改时,它将触发。

创建 Observables

首要任务是将 addListener 转换为 Observable。

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也监听这条新路径。同样,如果路径被删除,我不知道如何使返回的可观察对象取消订阅已删除的路径。

管道到主题(错误的方法)

我考虑过返回一个 Subject,并在父 MVCArray<MVCArray<LatLng>> 更改时简单地将它订阅到不同的 observables。

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;

这行得通,问题是对原始 Observable(和 addListener)的订阅就在这个方法中发生,而不是在订阅返回的 Observable 时发生。

结论

为此我需要某种运算符。

如果我对你的问题理解正确,可能会有space使用switchMap解决。

你说“问题是 MVCArray 的父 MVCArray 可以改变,但是 combineLatest 接受一个静态数组”。我认为您引用的静态数组是由 pathChanges$ Observable 发出的,它在代码片段的开头一次性创建,并且在 MVCArray 的父 MVCArray 更改时不会更新。

如果我的理解是正确的,我们需要做的是提供一种方法来通知MVCArray 的父MVCArray 发生变化的事件,并在任何时候发生此类事件时,再次执行combineLatest 函数使用新的更新数组。

这可以通过类似于以下的逻辑来完成

const pathsChanges$ = this.createMVCEventObservable(paths);

pathsChanges$
.pipe(
   switchMap(() => combineLatest(paths.getArray().map(this.createMVCEventObservable))),
   map(pathArr => new PolygonPathEvent(pathArr, paths))
)

这个逻辑假设变量paths是从外部传入这段逻辑的。

我无法重现这个案例,因此我不确定我的回答是否能解决您的问题,即使我希望它能有所帮助。