【问题标题】:Convert Dynamic Array of Dynamic Arrays to an Observable将动态数组的动态数组转换为 Observable
【发布时间】: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&lt;MVCArray&lt;LatLng&gt;&gt; 更改时简单地将其订阅到不同的可观察对象。

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运营商吗?您可以订阅其中的更改并返回主题。
  • 调查过了,但这不是正确的解决方案。目前正在考虑自定义运算符。

标签: rxjs reactivex


【解决方案1】:

如果我理解你的问题,可能有空间使用switchMap来解决它。

你说“问题是 MVCArray 的父 MVCArray 可以改变,但是 combineLatest 接受一个静态数组”。我认为您引用的静态数组是由pathChanges$ Observable 发出的,它在您的代码 sn-p 开始时创建一次,并且在 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是从外部传入这个逻辑的。

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

【讨论】:

    猜你喜欢
    • 2019-06-07
    • 2020-08-25
    • 2016-04-07
    • 2019-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多