【问题标题】:How to dynamically chain function calls using RXJS?如何使用 RXJS 动态链接函数调用?
【发布时间】:2016-04-19 20:06:51
【问题描述】:

我需要在第一次调用时缓存请求的结果,然后为后续调用读取缓存值。

为了实现这个目标,我正在使用 Promise 并将它们链接起来。我有一个可行的解决方案,但我想将其转换为 RxJS 的 observables 而不是 Promises。

这是我的工作解决方案:

private currentPromise: Promise<{ [key: string]: any }>;
private cache: any;
public getSomething(name: string): Promise<number>{
  return this.currentPromise = !this.currentPromise ? 
    this._getSomething(name) : 
    new Promise((r) => this.currentPromise.then(() => this._getSomething(name).then((res) => r(res))));
}

private _getSomething(name: string): Promise<any> {
  return new Promise((resolve) => {
    if (this.cache[name]) {
      this.messages.push("Resolved from cache");
        resolve(this.cache[name]);
      } else {
        // Fake http call. I would use Angular's Http class.
        setTimeout(()=> {this.messages.push("Resolved from server"); this.cache[name] = name; resolve(this.cache[name]); }, 2000 );
      }
  });
}

this.getSomething("thing1").then((res)=>this.messages.push(res));
this.getSomething("thing1").then((res)=>this.messages.push(res));
this.getSomething("thing2").then((res)=>this.messages.push(res));
this.getSomething("thing2").then((res)=>this.messages.push(res));
this.getSomething("thing1").then((res)=>this.messages.push(res));
this.getSomething("thing2").then((res)=>this.messages.push(res));
this.getSomething("thing1").then((res)=>this.messages.push(res));
this.getSomething("thing2").then((res)=>this.messages.push(res));

你可以在这个 plunkr 上测试它:https://plnkr.co/edit/j1pm2GeQf6oZwRvbUsXJ?p=preview

如何使用 RxJS 5 beta 实现相同的目标?

更新

按照 Bergi 的 cmets,我更新了我的 plunkr 和我的代码,使其更接近我的真实案例

【问题讨论】:

  • "new Promise((r) =&gt; this.currentPromise.then(() =&gt; this._getSomething(params).then((res) =&gt; r(res))));" - 什么?这应该做什么(和:don't do it)?为什么不直接返回currentPromise
  • 如果您已经缓存了currentPromise,则无需额外缓存.cache中的值本身。不要过于复杂。
  • @Bergi 每次调用“getSomething”时,我都会在 currentPromise 中附加一个新的“.then()”,因此所有“getSomething”调用都按照它们被调用的顺序执行。第一个调用从服务器获取数据并缓存它。随后的调用从缓存中返回数据。
  • 您不需要多次执行它们 - 您已经在currentPromise 中获得了第一次调用的(承诺)结果。您可以简单地多次返回它。它将按照它们被隐式附加的相同顺序调用所有回调。
  • 我在现实世界的情况下,每次都必须调用 _getSomething,因为“params”可以改变结果。我的缓存实际上是一个字典。因此,如果我调用 getSomething("thing1") 它将检查“thing1”是否已经在缓存中,如果没有,它将调用服务器。

标签: javascript typescript promise rxjs rxjs5


【解决方案1】:

AsyncSubjects 是 Promises 的 Rx 模拟。 publishLast 是将 observable 转化为 observable 的最佳方式。这样的事情应该可以工作:

private cache: {string: Rx.Observable<any>};

public getSomethings(names: string[]) : Rx.Observable<any> {
    // call getSomething for each entry in names
    // streams is an array of observables
    const streams = names.map(name => this.getSomething(name));

    // transform streams into an observable with an array of results
    return Observable.zip(streams);
}

public getSomething(name: string) : Rx.Observable<any> {
    if (!this.cache[name]) {
        // create the request observable
        // const request = Rx.Observable.ajax(...); // http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-ajax
        // for now, just wait 2 seconds and return name
        const request = Rx.Obsevable.of(name).delay(2000);

        // use "do" to log whenever this raw request produces data
        const loggedRequest = request.do(v => this.messages.push("retrieved from server " + v));

        // create an observable that caches the result
        // in an asyncSubject
        const cachedRequest = loggedRequest.publishLast();

        // store this in our cache object
        this.cache[name] = cachedRequest;
    }

    // return the cached async subject
    return this.cache[name];
}


// usage
this.getSomething("thing1").subscribe(v => this.messages.push("received " + v));
this.getSomething("thing1").subscribe(v => this.messages.push("received " + v));
this.getSomething("thing1").subscribe(v => this.messages.push("received " + v));
this.getSomething("thing1").subscribe(v => this.messages.push("received " + v));

【讨论】:

  • 谢谢,这非常有用。我知道我的问题中没有包含这一点,但是您将如何处理“getSomething”可以接收一系列要获取参数的东西的情况。示例:getSomething(["thing1", "things2"]) 将从服务器获取两者,然后 getSomething(["thing1", "thing3"]) 将从缓存返回 thing1,从服务器返回 thing3。
  • 你希望 observable 产生什么?一组结果?
  • 没错。我不确定它是如何工作的,但我猜它会使用 next() 来聚合数组中的“事物”,然后调用 complete() 函数以在订阅者准备好时触发它们。
  • 我添加了一个getSomethings,它展示了如何获取一个输入数组并返回一个可观察对象,该可观察对象生成一个包含结果的数组。它为每个项目使用getSomething,因此您仍然可以获得缓存优势。
  • 感谢您的更新。您的解决方案效果很好,但它仍然不适合我的情况。服务器实际上获取字符串数组并返回一个“事物”数组。示例:让我们说“thing1”和“thing2”被缓存。然后我调用 getSomethings(["thing1","thing2","thing3","thing4"]),它必须将 ["thing3","thing4"] 发送到服务器,等待响应然后组合 ["thing1 ", "thing2"] 来自缓存, ["thing3","thing4"] 来自服务器。最后,我希望能够在应用程序启动时预加载我的一些“东西”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-07
  • 2018-05-11
  • 1970-01-01
  • 2019-10-07
  • 1970-01-01
相关资源
最近更新 更多