首页 > 解决方案 > 如何比较两个冷 Observable 的源(而不是它们发出的潜在流)

问题描述

场景:我正在使用 publishReplay 来缓存和重播 Angular 应用程序中的某些 Http 请求(由于一些已经在 rxjs 中修复的错误,使用 publishReplay 而不是 shareReplay)。

我的问题是,如果我检测到 URL 参数更改,我想强制缓存的 observable 源更新自身并使用 publishReplay 创建一个新的缓存 observable。我想也许这可以通过询问/比较新提出的可观察对象与现有缓存的可观察对象的源来实现,但我没有成功实现这一点。

我在寻找什么: 一种询问可观察对象来源的方法,以便我可以将其与另一个可观察对象的来源进行比较,以查看它们是否相同(在本例中为 url),或者其他一些检测 Http Observable 上的 url 的方法随 publishReplay 改变。此外,我试图将这个逻辑抽象到一个缓存机制中,这样我就不必在整个应用程序中散布代码来检测参数是否发生变化。

这是一个非常幼稚的示例,说明我想做的事情不起作用,输入源参数是新的 Observable ,其中包含一个 http 请求的句柄,而 origSource 是以前的 observable 包含相同的(尽管可能使用 publishReplay 似乎不承认的不同 url 参数)。

  // determine if key exists and source is un-modified (i.e params did not change)
protected isEntreeValid<T>(key: ICacheKeyConstantsModel, source: Observable<T>): boolean {
    if (!this.has(key)) { return false; }
    if (this.has(key)) {
        let origSource = this.cache.registry.get(key).source; // observable previously cached used to resubscribe to later and returned cached publishReplay response, or can be tickled to make the original http request again effectively busting the cache.
        console.log('source: ', source);
        console.log('are they equal', source.source === origSource.source); //always returns false but assume need to check some inner value of observable anyways and do a fuzzy comparison.
        if (source.source !== origSource.source) { return false; }
    }

    return true;
}

上述方法:上述方法中的输入“源”参数只是一个指向 http.get 方法的指针,并以键/值对方式存储在 Map 中:即 Map,以便我们可以集中编组它们的缓存状态和其他属性方式更容易。基本上就是在这里,如果“键”已经存在,我想评估“源”以查看 URL 上的参数是否更改,因此如果它们有我们可以破坏缓存,或者如果它们没有,我们将返回publishReplay 结果。

注意:在这种情况下,我不打算/不想连接到 Observable,我只对比较这些 Observable 的来源感兴趣,而不是它们将发出的潜在流。

更新:找到了我要找的东西,虽然不知道为什么它在那里是 WAAAY。有没有一种巧妙的迭代方式,似乎在结构上与 Observables 一致,而不是我在创建这些时所做的奇怪事情的产物。确实看起来很奇怪,这个非常基本的信息会在那里很远(注意 url 已经被混淆了,这个例子没有参数):

属性位置是: Observable.value.source.source.source.source.source

该位置的对象结构为:

{

value: HttpRequest

body: null

headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, headers: Map(0)}

method: "GET"

params: HttpParams {updates: null, cloneFrom: null, encoder: HttpUrlEncodingCodec, map: Map(0)}

reportProgress: false

responseType: "json"

url: "https://my-dev-server.com/primary/HealthCareApp/Patients"

urlWithParams: "https://my-dev-server.com/primary/HealthCareApp/Patients"

}

问题:任何干净/可靠的方法来展平,或深入到最内部的 Observable 而不订阅?

更新 2:

现在我正在使用类似下面的方法来提取 innerObservable,可能有更好的方法,但这是我们目前正在使用的方法:

// retrieve inner meta-data from cold observable for interrogation without subscribing
private extractInnerObservable<T>(source: Observable<T>): Observable<T> {
    let target = observableOf(source)['value'];
    while (target['source']) {
        target = target['source'];
    }

    return target;
}

结果方法:

在此处输入图像描述

结论:仍然可以肯定地探索其他选项,但是我已经多次更新了这个问题,以分享我现在所处的状态,至少现在它解决了原始问题(尽管肯定不是以最优雅的方式)。但是,如果其他人正在为类似的事情而苦苦挣扎,那么分享一些这种疯狂最终导致的结果是有价值的。

标签: angulartypescriptrxjs6

解决方案


我会争辩在这里颠倒你的逻辑。如果有一些参数通过你想要更改缓存的请求,然后使用操作符来做......

private paramSource = new Subject<string>(); // whatever type is appropriate
cached$ = this.paramSource.pipe(
  distinctUntilChanged(), // could add some custom compare function in here
  switchMap(param => this.makeRequest(param)),
  shareReplay(1) // whatever you wana do for caching
);

// call this whenever you might've wanted to run the observable inspection
updateParam(param: string) {
  this.paramSource.next(param);
}

如果这直接实现了您的目标,则不是积极的,因为我不太清楚您的目标是什么,但希望这很接近。


推荐阅读