Rxjs可观察订阅的数量

时间:2016-09-04 09:58:19

标签: angular rxjs observable

在我的Angular 2应用程序中,我有许多可观察和订阅。 当然,当我离开页面时,我应该取消订阅,但是我试图找出是否有可能获得有效订阅的数量。 仅用于调试信息或忘记取消订阅时。

rxjs中是否有此类信息?

4 个答案:

答案 0 :(得分:3)

可能有点晚了,但是您可以利用rxjs-spy的帮助。

此解决方案与建议的解决方案等效,并且在我看来,维护性更好。

通常,我会在main.ts中全局启用它,将其作为一种即发即弃策略。您只需要:

  1. 通过包管理器安装rxjs-spy
  2. 在main.ts中导入对创建函数的引用:import { create } from 'rxjs-spy';
  3. 在角度初始化代码段之后立即在调试版本中初始化rxjs-spy:

`

if (environment.production) {
    enableProdMode();
}
else {
    //we enable RXjs Spy on non production bulds only
    const spy = create();
    // we call show for two purposes: first is to log to the console an empty snapshot so we can see that everything is working as expected, then to suppress unused variable usage (the latter is a convention on mine)
    spy.show();
}

`

  1. 给您的观察者一个名字:

`

import { tag } from 'rxjs-spy/operators';

...

// This is a sample method which asks for a "Product" entity. Product and this.http is omitted as the focus is on tagging the observable
public getProductById(productId: number): Observable<Product> {
    let params = new HttpParams()
        .append('productId', productId.toString())
        ;
    // we tag the returned observable with the name 'getProductById' (this is a convention on mine, you can choose whatsoever name)
    return this.http.get<Product>(this.baseUrl + "api/product", { params: params }).pipe(tag("getProductById"));
}

`

  1. 当您需要查看rxjs状态时,只需打开控制台窗口并使用rxSpy.show()即可获取当前快照

您可以使用其他命令。非常详细的教程是Debugging with rxjs Spy

(如果有人阅读此答案后能够解决格式问题,我感到很高兴,因为我无法在列表中正确找到格式)

答案 1 :(得分:2)

在您的情况下,您可以通过refCounting充分利用RxJS主题。您可以为Subject提供可观察的源,并让refCount管理其订阅。 如果没有观察者收听,refCount将取消订阅您的源可观察对象。另一方面,如果观察者计数为0并且观察者订阅了它,则会创建新的source observable实例。

主体将充当观察者和观察源之间的代理,并管理订阅和取消订阅。本质上它是如何工作的是当你的第一个观察者订阅你的主题时,主题依次订阅你的源可观察量(refCount从0变为1)。主体允许多个观察者监听单播源可观察性使其成为多播。当观察者开始取消订阅并且refCount再次降至0时,主体本身将取消订阅源可观察数据。

在代码中可以更好地理解:

&#13;
&#13;
const {
  Observable
} = Rx;

let sourceObservable = Observable
  .create((observer) => {
    let count = 0;
    let interval = setInterval(() => {
      observer.next(count++)
    }, 700);

    setTimeout(() => {
      clearInterval(interval);
      observer.complete();
    }, 5500);

    return () => {
      clearInterval(interval);
      console.log('######## Source observable unsubscribed');
    }
  })
  .do((x) => console.log('#### Source emits: ' + x));

let subject = sourceObservable
  .share()
  //.do((x) => console.log('#### Subject emits: ' + x))
  ;

let pageOneObserver;
let pageTwoObserver;
let pageThreeObserver;

setTimeout(() => {
  console.log('pageOneObserver will subscribe');
  pageOneObserver = subject.subscribe({
    next: (x) => {
      console.log('pageOneObserver gets: ' + x);
    },
    complete: () => {
      console.log('pageOneObserver: complete');
    }
  });
}, 1000);

setTimeout(() => {
  console.log('pageTwoObserver will subscribe');
  pageTwoObserver = subject.subscribe({
    next: (x) => {
      console.log('pageTwoObserver gets: ' + x);
    },
    complete: () => {
      console.log('pageTwoObserver: complete');
    }
  });
}, 4000);

setTimeout(() => {
  console.log('pageOneObserver will unsubscribe');
  pageOneObserver.unsubscribe();
}, 7000);

setTimeout(() => {
  console.log('pageTwoObserver will unsubscribe');
  pageTwoObserver.unsubscribe();
}, 10000);

setTimeout(() => {
  console.log('pageThreeObserver will subscribe');
  pageThreeObserver = subject.subscribe({
    next: (x) => {
      console.log('pageThreeObserver gets: ' + x);
    },
    complete: () => {
      console.log('pageThreeObserver: complete');
    }
  });
}, 13000);

setTimeout(() => {
  console.log('pageThreeObserver will unsubscribe');
  pageThreeObserver.unsubscribe();
}, 16000);
&#13;
<script src="https://unpkg.com/rxjs@5.1.1/bundles/Rx.min.js"></script>
&#13;
&#13;
&#13;

有一些创作主题的简写方法。例如:

sourceObservable.share();
// is the same as
sourceObservable.publish().refCount();
sourceObservable.publish().refCount();
// is the same as
sourceObservable.multicast(new Rx.Subject()).refCount();
sourceObservable.publishReplay().refCount();
// is the same as
sourceObservable.multicast(new Rx.ReplaySubject(1)).refCount();
sourceObservable.publishBehavior().refCount();
// is the same as
sourceObservable.multicast(new Rx.BehaviorSubject(0)).refCount();
sourceObservable.publishLast().refCount();
// is the same as
sourceObservable.multicast(new Rx.AsyncSubject()).refCount();

sourceObservable.share();还内置了主题工厂,这意味着当源observable在某些时候完成时,我们必须创建一个sourceObservable的新实例,但只能使用你的主题的新实例来完成选择。使用下面的其他可用主题,我们必须明确地将工厂函数返回给多播运算符。

如果您想使用除Rx.Subject()之外的其他主题类型并且想要使您的可观察订阅真正可重用,您必须使用主题工厂(这只是一个返回您喜欢的任何主题的新实例的函数)使用),如下图所示:

&#13;
&#13;
const {
  Observable
} = Rx;

let sourceObservable = Observable
  .create((observer) => {
    let count = 0;
    let interval = setInterval(() => {
      observer.next(count++)
    }, 700);

    setTimeout(() => {
      clearInterval(interval);
      observer.complete();
    }, 5500);

    return () => {
      clearInterval(interval);
      console.log('######## Source observable unsubscribed');
    }
  })
  .do((x) => console.log('#### Source emits: ' + x));

/* You could return whatever subject instance you like here */
let subjectFactory = () => new Rx.ReplaySubject(1);

let subject = sourceObservable
	.multicast(subjectFactory)
	.refCount();
	//.do((x) => console.log('#### Subject emits: ' + x))
	;

let pageOneObserver;
let pageTwoObserver;
let pageThreeObserver;

setTimeout(() => {
  console.log('pageOneObserver will subscribe');
  pageOneObserver = subject.subscribe({
    next: (x) => {
      console.log('pageOneObserver gets: ' + x);
    },
    complete: () => {
      console.log('pageOneObserver: complete');
    }
  });
}, 1000);

setTimeout(() => {
  console.log('pageTwoObserver will subscribe');
  pageTwoObserver = subject.subscribe({
    next: (x) => {
      console.log('pageTwoObserver gets: ' + x);
    },
    complete: () => {
      console.log('pageTwoObserver: complete');
    }
  });
}, 4000);

setTimeout(() => {
  console.log('pageOneObserver will unsubscribe');
  pageOneObserver.unsubscribe();
}, 7000);

setTimeout(() => {
  console.log('pageTwoObserver will unsubscribe');
  pageTwoObserver.unsubscribe();
}, 10000);

setTimeout(() => {
  console.log('pageThreeObserver will subscribe');
  pageThreeObserver = subject.subscribe({
    next: (x) => {
      console.log('pageThreeObserver gets: ' + x);
    },
    complete: () => {
      console.log('pageThreeObserver: complete');
    }
  });
}, 13000);

setTimeout(() => {
  console.log('pageThreeObserver will unsubscribe');
  pageThreeObserver.unsubscribe();
}, 16000);
&#13;
<script src="https://unpkg.com/rxjs@5.1.1/bundles/Rx.min.js"></script>
&#13;
&#13;
&#13;

如果还有不清楚的事情,请随时询问。

答案 2 :(得分:0)

以下效用函数可能会有所帮助...

function subscriberCount<T>(sourceObservable: Observable<T>, description: string) {
  let counter = 0;
  return Observable.create((subscriber: Subscriber<T>) => {
    const subscription = sourceObservable.subscribe(subscriber);
    counter++;
    console.log(`${description} subscriptions: ${counter}`);

    return () => {
      subscription.unsubscribe();
      counter--;
      console.log(`${description} subscriptions: ${counter}`);
    }
  });
}

像这样使用:

const timer$ = subscriberCount(Observable.timer(1000), 'Timer');

每当订户数量发生变化时,控制台都会记录

答案 3 :(得分:-1)

在组件销毁后使用 this 操作取消订阅

示例:

ngOnInit() {
    interval(1000)
        .pipe(
            untilComponentDestroyed(this)       // <-- use the operator
        )
        .subscribe();
}