简体   繁体   English

如果另一个可观察对象在RxJS中具有数据,如何忽略所有可观察对象?

[英]How to ignore all from an observable if the other observable has data in RxJS?

I have two observables, one receives data from the browser localstorage and the other is from the database through WebAPI . 我有两个观察对象,一个是从浏览器localstorage接收数据,另一个是通过WebAPI数据库接收数据。

  1. I want to subscribe to them so if the observable from the localstorage has data, don't initiate the one to get the data from the database . 我要订阅它们,因此,如果从本地存储中观察到的数据中有数据,请不要启动该数据库以从数据库中获取数据。
  2. If the observable from the localstorage does not have any data, invoke the ajax call to get the data from the WebAPI . 如果从localstorage观察到的数据没有任何数据,请调用ajax调用以从WebAPI获取数据。

In the following example, I should get only 20, 40, 60, 80, 100 because the first observable has data. 在下面的示例中,我应该只获得20, 40, 60, 80, 100因为第一个可观察对象具有数据。 The second observable did not run because the first observable started emitting data. 第二个可观察对象未运行,因为第一个可观察对象开始发出数据。

在此处输入图片说明

You can use skipWhile and check for the data and return true or false. 您可以使用skipWhile并检查数据并返回true或false。

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

The local storage observable needs some way to signal that there is no data. 可观察到的本地存储需要某种方式来表示没有数据。 If it just "hangs" and never completes, then you might use a timer to complete it: 如果只是“挂起”而从未完成,则可以使用计时器来完成它:

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

This will start a timer and if the local storage observable does not produce a value within 1s, it will end the stream. 这将启动一个计时器,如果可观察的本地存储在1秒内未产生值,它将结束流。

If your local storage observable will complete on its own if there is no data, then you can use it as is: 如果没有数据,如果可观察的本地存储将自行完成,则可以按原样使用它:

const lsObservable2 = lsObservable;

At this point, we'd really like to use defaultIfEmpty , because that has the semantics you want. 在这一点上,我们真的很想使用defaultIfEmpty ,因为它具有您想要的语义。 Unfortunately it only supports a scalar value for the default, when instead you want to yield a different observable stream. 不幸的是,它仅支持默认值的标量值,而当您想产生不同的可观察流时。 So lets write our own version of defaultIfEmpty which produces a new stream using Observable.defer . 因此,让我们编写我们自己的defaultIfEmpty版本,它使用Observable.defer生成一个新的流。 We use defer so that each time someone subscribes, we can create a new closure variable ( hasValue ) and monitor whether or not the source observable produces a value for this subscription 我们使用defer以便每次有人订阅时,我们都可以创建一个新的闭包变量( hasValue ),并监视可观察的源是否为此订阅生成一个值

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);
    });
}

Next, let's assume you've setup your db Observable to not issue the ajax call until it is actually subscribed. 接下来,假设您已将db Observable设置为在实际订阅之前不发出ajax调用。 This is an important step. 这是重要的一步。 Again you can use something like defer : 同样,您可以使用类似defer

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

Then we can use your new operator like so: 然后,我们可以像这样使用您的新运算符:

const data = lsObservable2.defaultObservableIfEmpty(dbObservable);

So your application code looks like this (once you've added the new operator to your library): 因此,您的应用程序代码如下所示(将新运算符添加到库中之后):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM