【问题标题】:Rxjs using first() with timer()Rxjs 使用 first() 和 timer()
【发布时间】:2020-12-08 05:40:09
【问题描述】:

我试图每 10 秒调用一次服务,但也想只在第一次发射时执行一些代码,这里的问题是第一个条目是重复的,这里是代码:

ionViewWillEnter() {
  this.isLoading = true;
  const Obs = timer(0, 10000).pipe(
    switchMap(() => {
      return this.serviceName.someFunc();
    })
  );
  this.timerSub = Obs.subscribe();
  this.timerSub = Obs.pipe(first()).subscribe(() => {
    this.isLoading = false;
  });
}

我还注意到另一个问题,即使我在离开页面时取消订阅,该服务仍然每 10 秒调用一次,感谢任何帮助。

更新

我找到了一个解决方案,但它更像是一种解决方法,基本上我所做的就是在订阅上设置一个 setTimeout :

this.timerSub = Obs.pipe(first()).subscribe(() => {
  this.isLoading = false;
});
setTimeout(() => {
  this.timerSub = Obs.subscribe();
}, 10000);

显然,取消订阅问题也得到了解决,尽管我希望能提供一些更优雅的解决方案的反馈,在此先感谢。

【问题讨论】:

  • @IngoBürk 这就是 first() 的用途,我等待第一个响应将加载设置为 false,然后我继续发送请求,我在 subscribe() 中得到响应。

标签: javascript angular ionic-framework rxjs


【解决方案1】:

更好的解决方案:

在顶部创建变量firstSub

ionViewWillEnter() {
  this.isLoading = true;
  this.timerSub = timer(0, 10000).pipe(
    switchMap(() => {
      return this.serviceName.someFunc();
    })
  );
  this.firstSub = this.timerSub.pipe(first());
  this.firstSub.subscribe(() => {
    // only emit once(first)
    this.isLoading = false;
  });
}

在组件视图销毁之前取消订阅。

ngOnDestroy(){
  this.timerSub.unsubscribe();
  this.firstSub.unsubscribe();
}

【讨论】:

  • 它似乎无法解决我的问题,因为有了这个,我只发送一次请求,但我想每 10 秒发送一次。
  • this.timerSub.subscribe(() => { // 每 10 秒执行一次 })
【解决方案2】:

Nilesh Patel 提供的答案应该可以正常工作,但我仍然想添加此答案以分享您可能需要在应用中使用的一些小技巧和改进。

请看一下这个Stackblitz demo

首先要注意的是,如果您正在使用 timer 运算符,并且您有兴趣在它第一次发出时做某事,您可以检查该运算符返回的值,看看它是否是 0

timer(0, 10000).pipe(
  tap(currentTimer => {
    if (currentTimer === 0) {
      this.someFunctionToRunOnlyOnce();
    }
  }),
  // ...
);

要记住的第二件事是,您可以创建一个主题并像这样使用takeUntil 运算符,而不是将每个订阅都存储在一个变量中(然后取消所有订阅):

private unsubscribe$: Subject<void> = new Subject<void>();

// ...

timer(0, 10000).pipe(
  // ... other operators
  takeUntil(this.unsubscribe$) // <-- like this
).subscribe();

// ...

ngOnDestroy() {
  this.unsubscribe$.next(); // <-- this will clean the streams
  this.unsubscribe$.unsubscribe(); // <-- this will clean the unsubscribe$ stream
}

要记住的另一件非常小的事情是,您可以随时“暂停”和“恢复”流,而不会“破坏”它。例如,您可以在离开页面时暂停它,然后在用户即将再次进入页面时使用filter 运算符再次恢复:

private isInPage: boolean = true;

// ...

timer(0, 10000).pipe(
  filter(() => this.isInPage),
  // other operators ...
);

// ...

ionViewWillEnter() {
  this.isInPage = true;
}

ionViewWillLeave() {
  this.isInPage = false;
}

所以把所有这些放在一起,它会是这样的:

import { Component, OnInit } from "@angular/core";
import { NavController } from "@ionic/angular";
import { Observable, of, Subject, timer } from "rxjs";
import { delay, filter, switchMap, takeUntil, tap } from "rxjs/operators";

@Component({
  selector: "app-home",
  templateUrl: "./home.page.html",
  styleUrls: ["./home.page.scss"]
})
export class HomePage implements OnInit {
  private isInPage: boolean = true;
  private unsubscribe$: Subject<void> = new Subject<void>();

  constructor(private navCtrl: NavController) {}

  ngOnInit() {
    timer(0, 10000)
      .pipe(
        filter(() => this.isInPage),
        tap(currentTimer => {
          if (currentTimer === 0) {
            this.someFunctionToRunOnlyOnce();
          }
        }),
        switchMap(() => {
          return this.someAsynFunction();
        }),
        takeUntil(this.unsubscribe$)
      )
      .subscribe();
  }

  ionViewWillEnter() {
    this.isInPage = true;
  }

  ionViewWillLeave() {
    this.isInPage = false;
  }

  ngOnDestroy() {
    this.unsubscribe$.next();
    this.unsubscribe$.unsubscribe();
  }

  public openDetailsPage(): void {
    this.navCtrl.navigateForward("details");
  }

  private someAsynFunction(): Observable<number> {
    const randomNumber = Math.floor(Math.random() * 10000) + 1;

    console.log("==> Running someAsynFunction method");
    return of(randomNumber).pipe(delay(1000));
  }

  private someFunctionToRunOnlyOnce(): void {
    console.log("==> Running someAsynFunctionToRunOnlyOnce method");
  }
}

【讨论】:

  • 谢谢!这些提示也非常有用,因为我不知道它们中的任何一个哈哈,尤其是“currentTimer”,它早就解决了我的问题,我也喜欢你清理流的方式,谢谢。
猜你喜欢
  • 2020-06-21
  • 2014-11-30
  • 1970-01-01
  • 2020-12-28
  • 2017-02-14
  • 2020-06-23
  • 2018-04-09
  • 2016-04-23
  • 1970-01-01
相关资源
最近更新 更多