简体   繁体   中英

RxJs Observable without next events?

How can I create an RxJs observable that only emits a complete event and no next events?

I have an observable that performs some operations which has a side effect in which it populates an in-memory cache. I would like to use this observable as a semaphore so that a second observable only starts executing when it is complete. Then a second observable can use this cache to decorate incoming data. My idea is to use concat where the first observable only emits a complete event:

const cache = {};
const firstObservable = // fetch data to be cached
const secondObservable = // fetch other data that will be decorated with cached data

// add all next events of the first observable to the cache
const promise = firstObservable
   .forEach(
      data => {
         cache[data.key] = data;
      }
   );

// create a new observable that only emits a complete event
const waitForCache = of(promise)
   .pipe(
      // skip the first event from waitForCache (the empty promise event), 
      // since we are only interested in when the population of the cache is complete
      skip(1)
   );

// create a semaphore that waits for the complete event from the cache population 
// before dealing with the second observable
const decorated = concat(waitForCache, secondObservable)
   .pipe(
      map(
         data => {
            // decorate objects with data from cache
            return Object.assign({}, data, cache[data.key]);
         }
      ));

My assumption is that the problem is the skip(1) call.

  • With the implementation above, the waitForCache completes too early and the cache is empty when the second observable attempts to fetch the value. Notably, the cache will be populated after the decoration has been made.
  • When removing skip, the waitForCache observable will add an additional (empty) event to the decorated observable

I decided to re-implement my solution to subscribe to both observables and then use a filter to discard the events from the firstObservable (that were added to the cache) so that only the events from the secondObservable are affected by the mapping function:

const cache = {};
const firstObservable = // fetch data to be cached
const secondObservable = // fetch other data that will be decorated with cached data

// add all next events of the first observable to the cache
const waitForCache = firstObservable
   .pipe(
      tap({
         next: data => {
            cache[data.key] = data;     
         }
      });

// use concat so the cache population is completed before dealing with the second observable
const decorated = concat(waitForCache, secondObservable)
   .pipe(
      filter(
         data => { return /* check for some specific property that is 
                             available in one observable, but not the other */ } 
      )
      map(
         data => {
            // decorate objects with data from cache
            return Object.assign({}, data, cache[data.key]);
         }
      ));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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