检查publishReplay()。refCount()是否有观察者

时间:2018-04-23 08:45:45

标签: rxjs

我定义了一个像这样的Observable:

const obs$ = Observable.create(...)
  .publishReplay(1)
  .refCount();

因此它在我的源Observable和所有观察者之间放置一个ReplaySubject(1)。

由于ReplaySubject在其状态中具有观察者数量(通过其observers数组属性),如何从obs$访问ReplaySubject?

我实际上只需知道obs$是否有观察员。 RxJS4在Subject上有a hasObservers() method,但它在RxJS5中删除了。我怎样才能用RxJS5实现这个目标?

2 个答案:

答案 0 :(得分:2)

不确定您的用法,但根据我的需要,我创建了一个自定义操作符,允许我根据refCount的状态透明地执行副作用(类似于点击)。它只是进行传递订阅并对子/ unsub进行打孔。回调获取当前的refCount和前一个,以便您可以告诉状态和方向。我喜欢使用运算符,因为我可以在流中的任何位置插入它。如果您只是想要一个二进制输出,是否有任何订阅,可以很容易地修改它。

const { Observable, Observer, interval } = rxjs;
const { publishReplay, refCount } = rxjs.operators;

const tapRefCount = (onChange) => (source) => {
  let refCount = 0;

  // mute the operator if it has nothing to do
  if (typeof onChange !== 'function') {
    return source;
  }
  // mute errors from side-effects
  const safeOnChange = (refCount, prevRefCount) => {
    try {
      onChange(refCount, prevRefCount);
    } catch (e) {
    }
  };
  
  // spy on subscribe
  return Observable.create((observer) => {
    const subscription = source.subscribe(observer);
    const prevRefCount = refCount;
    refCount++;
    safeOnChange(refCount, prevRefCount);
    
    // spy on unsubscribe
    return () => {
      subscription.unsubscribe();
      const prevRefCount = refCount;
      refCount--;
      safeOnChange(refCount, prevRefCount);
    };
  });
};

const source = interval(1000).pipe(
  publishReplay(1),
  refCount(),
  tapRefCount((refCount, prevRefCount) => { console.log('refCount', refCount, prevRefCount > refCount ? 'down': 'up'); })
);

const firstSub = source.subscribe((x) => { console.log('first', x); });
let secondSub;
setTimeout(() => {
  secondSub = source.subscribe((x) => { console.log('second', x); });
}, 1500);
setTimeout(() => {
  firstSub.unsubscribe();
}, 4500);
setTimeout(() => {
  secondSub.unsubscribe();
}, 5500);
<script src="https://unpkg.com/rxjs@rc/bundles/rxjs.umd.min.js"></script>

打字稿版本:

import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';

export const tapRefCount = (
  onChange: (refCount: number, prevRefCount: number) => void
) => <T>(source: Observable<T>): Observable<T> => {
  let refCount = 0;

  // mute the operator if it has nothing to do
  if (typeof onChange !== 'function') {
    return source;
  }

  // mute errors from side-effects
  const safeOnChange = (refCount, prevRefCount) => {
      try {
        onChange(refCount, prevRefCount);
      } catch (e) {
    }
  };

  // spy on subscribe
  return Observable.create((observer: Observer<T>) => {
    const subscription = source.subscribe(observer);
    const prevRefCount = refCount;
    refCount++;
    safeOnChange(refCount, prevRefCount);

    // spy on unsubscribe
    return () => {
      subscription.unsubscribe();
      const prevRefCount = refCount;
      refCount--;
      safeOnChange(refCount, prevRefCount);
    };
  }) as Observable<T>;
};

答案 1 :(得分:1)

Subject类有一个名为observers的公共属性(请参阅https://github.com/ReactiveX/rxjs/blob/5.5.10/src/Subject.ts#L28

所以你可以使用:

const s = new Subject();

...

if (s.observers.length > 0) {
  // whatever
}

请注意refCount会返回一个Observable,因此您无法完成我上面提到的操作。但是,您可以将自己的主题实例作为第三个参数提供给publishReplay,并在其上使用s.observers,请参阅http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-publishReplay