In Angular 11, how do you set a timer with RXJS (e.g. avoid "TypeError: You provided 'undefined' where a stream was expected" errors)

In Angular 11, how do you set a timer with RXJS (e.g. avoid "TypeError: You provided 'undefined' where a stream was expected" errors)

我最近刚升级到 Angular 11.2.9 和 RXJS 6.6.7。我的组件中有这个 ...

  ngOnInit(): void {
    window.addEventListener('blur', this.onBlur, false);
    ...
  }
  ...



  onBlur(): void {
    this.trendingSet$ = timer(1, HotComponent.REFRESH_INTERVAL_IN_MS).pipe(
      switchMap(() => this.apiService.getTrending()),
      retry(),
      share(),
      takeUntil(this.stopPolling)
    );
    console.log(this.trendingSet$);
    this.trendingSet$.subscribe((result: TrendingSet) => {
      this.articleStats = result.trending_articles;
    });
  }

但是,我在

上收到此错误
this.trendingSet$.subscribe((result: TrendingSet) => {

行:

ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
    RxJS 4
    onBlur hot.component.ts:90
    Angular 14
    ngOnInit hot.component.ts:35
    Angular 21
    RxJS 5
    Angular 8
        emit
        checkStable
        onHasTask
        hasTask
        _updateTaskCount
        _updateTaskCount
        runTask
        drainMicroTaskQueue
core.js:6210
    Angular 3
    RxJS 5
    Angular 20
    RxJS 10
    onBlur hot.component.ts:90
    Angular 14
    ngOnInit hot.component.ts:35
    Angular 21
    RxJS 5
    Angular 8

在我的组件中设置计时器以定期查询服务方法的正确方法是什么?

不要使用 window.addEventListener('blur', this.onBlur, false) 当你有 rxjs 包裹 fromEvent...

这里最初的问题是,当您调用 onBlur 作为 'blur' 事件的回调时,指针 this(在 this[=30= .trendingSet$) 将指向 Window 对象而不是你的组件,在这种情况下你必须使用 window.addEventListener('blur', this.onBlur.bind (this), false)

此外,share 运算符在这里是多余的,除非您也在其他地方使用流 this.trendingSet$

编辑

private startPolling$ = new Subject();
private stopPolling$ = new Subject();

// Using this logic, subscription to blur event will be automatically unsubscribed once Component is being destroyed
@HostListener('window:blur', ['$event'])
onBlurEvent(): void {
    this.startPolling$.next();
}

ngOnInit() {

    const poll$ = timer(1, HotComponent.REFRESH_INTERVAL_IN_MS)
        .pipe(switchMap(() => this.apiService.getTrending()), retry());

    this.startPolling$.pipe(
        switchMap(() => poll$),
        takeUntil(this.stopPolling$)
    ).subscribe((response) => {
        // Doing stuff with response
    });
}

或者不使用 @HostListener 你可以使用

    const poll$ = timer(1, HotComponent.REFRESH_INTERVAL_IN_MS)
        .pipe(switchMap(() => this.apiService.getTrending()), retry(), 
        takeUntil(this.stopPolling$));

    fromEvent(document, 'blur').pipe(
       switchMap(() => poll$),
   ).subscribe((response) => {
      // Doing stuff with response
   });