我试图每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);
很明显,取消订阅的问题也得到了解决,尽管我很感激能提供一些更优雅的解决方案,提前谢谢。
Nilesh Patel提供的答案应该很好,但我仍然想添加这个答案,以分享您可能需要在应用程序中使用的一些小技巧和改进。
请看一下Stacklitz演示。
首先要注意的是,如果您正在使用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");
}
}
更好的解决方案:
在顶部创建变量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();
}