【问题标题】:How to ignore all from an observable if the other observable has data in RxJS?如果另一个可观察对象在 RxJS 中有数据,如何忽略所有可观察对象?
【发布时间】:2017-04-01 00:38:44
【问题描述】:

我有两个 observable,一个从浏览器 localstorage 接收数据,另一个通过 WebAPI数据库 接收数据。

  1. 我想订阅它们,因此如果 localstorage 中的 observable 有数据,请不要启动从 数据库 中获取数据的 observable。
  2. 如果 localstorage 中的 observable 没有任何 数据,调用 ajax 调用以从 WebAPI 获取数据。

在下面的例子中,我应该只得到20, 40, 60, 80, 100,因为第一个 observable 有数据。第二个 observable 没有运行,因为第一个 observable 开始发出数据。

【问题讨论】:

  • 您希望本地存储 observable 发出多少值?大概只有一个;在这种情况下,问题是这个问题的欺骗:stackoverflow.com/a/39200507/6680611
  • 我想要我在问题中提到的那个 observable 中的所有值。他们是20,40,60,80,100
  • 您的大理石图不代表上面提出的问题。在图中,两个流同时开始,并且您已声明底部流将被忽略。然而,在上面的问题中,您声明如果 localstorage observable 有数据,则不会启动 ajax observable 。此外,您没有定义“有数据”的含义。 localstorage observable 是否完成?不清楚你在问什么。
  • 大理石图只是显示有两个流的指南。如果第一个 observable/stream 有数据,则不应启动第二个 ajax observable/stream。 localstorage observable 可以或不可以有数据。它更像是本地缓存的数据。当应用程序启动时不会有任何数据。 ajax observable 从服务器带进来的数据会被写入本地存储。从下一次开始,应用程序将从本地存储 observable 中获取数据。

标签: javascript rxjs observable


【解决方案1】:

本地存储 observable 需要某种方式来表示没有数据。如果它只是“挂起”并且从未完成,那么您可以使用计时器来完成它:

// Use .amb() instead of .race() if your rxjs version is old
const timer = Observable.timer(1000).ignoreElements();
const lsObservable2 = Observable.race(lsObservable, timer);

这将启动一个计时器,如果本地存储 observable 在 1s 内没有产生值,它将结束流。

如果你的本地存储 observable 在没有数据的情况下会自行完成,那么你可以按原样使用它:

const lsObservable2 = lsObservable;

此时,我们真的很想使用defaultIfEmpty,因为它具有您想要的语义。不幸的是,它只支持默认的标量值,而当您想要产生不同的可观察流时。所以让我们编写我们自己的defaultIfEmpty 版本,它使用Observable.defer 生成一个新流。我们使用defer,这样每次有人订阅时,我们都可以创建一个新的闭包变量(hasValue)并监控源 observable 是否为此订阅产生值

Observable.prototype.defaultObservableIfEmpty = function(defaultObservable) {
    const source = this;
    return Observable.defer(() => {
        let hasValue = false;
        // create a deferred observable that will evaluate to
        // defaultObservable if we have not seen any values, or
        // empty observable if we have seen any values.
        const next = Observable.defer(() => hasValue ? Observable.empty() : defaultObservable);

        // now use do() to set hasValue to true if we see a value from
        // the source observable
        const sourceSetsValue = source.do(v => hasValue = true);

        // now we can can just concat this sourceSetsValue
        // with out "next" observable.  When the first observable
        // finishes, it will subscribe to "next", which will then
        // either produce the defaultObservable or an empty observable
        return sourceSetsValue.concat(next);
    });
}

接下来,假设您已将 db Observable 设置为在实际订阅之前不发出 ajax 调用。这是重要的一步。你可以再次使用defer

const dbObservable = Observable.defer(() => makeDbCall());

然后我们可以像这样使用你的新运算符:

const data = lsObservable2.defaultObservableIfEmpty(dbObservable);

所以您的应用程序代码如下所示(一旦您将新运算符添加到库中):

const timer = Observable.timer(1000).ignoreElements();
const lsObservable2 = Observable.race(lsObservable, timer);
const dbObservable = Observable.defer(() => makeDbCall());
const data = lsObservable2.defaultObservableIfEmpty(dbObservable);

【讨论】:

    【解决方案2】:

    您可以使用 skipWhile 并检查数据并返回 true 或 false。

    observableObject.skipWhile((data)=> {
          if(data){
              return false;
          }
    });
    

    【讨论】:

    • 这只适用于一个 observable。问题中有两个 observables。
    • 你能详细说明一下吗?
    • 你可以看看这个question。我认为这两个问题都试图解决类似的问题。但在我的问题中,如果缓存已经有数据,我想取消或不启动 promise/ajax 调用。
    猜你喜欢
    • 2022-08-19
    • 2020-06-03
    • 2019-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-12
    • 1970-01-01
    相关资源
    最近更新 更多