如果我的观察对象需要很长时间才能执行。我们将其称为longObservable
,其类型为Observable,执行时间为5秒钟,每次执行时,它仅发出一次新字符串,然后完成。
longObservable(): Subject<string> {
return timer(5000).pipe{
map(() => randomString())
}
}
和其他一些页面多次调用它。如果正在处理中,我只想继续执行一个过程。如果完成,我想重新开始。
longObservable.subscribe() // Immediate, start the timer
,这将在两秒钟后运行:
longObservable.subscribe() // Get the same string as
// the above subscription in 3 seconds.
这会在20秒后运行
longObservable.subscribe() // Start a new iteration and wait
// 5 seconds, get a new string.
我认为第二个订阅很容易,它将按我想要的方式工作。这是我遇到的第三个问题。由于longObservable
完成,它将立即发出与其他两个相同的值。
这用于设备上的地理位置。我想请求一个新位置,但是如果已经有一个请求在进行中,请使用该结果。
编辑:将可观察对象更改为多播对象,删除了take(1)。
Edit2:https://stackblitz.com/edit/angular-venpk4是我想要的工作示例。我希望在没有timerRunning变量和RxJS运算符的情况下完成此操作。它位于hello组件下,并打印到控制台。
答案 0 :(得分:2)
棘手的问题。这是我在StackBlitz中的解决方案。 share()
运算符是几个关键点,它可以将可观察对象有效地转换为主题,而不必显式声明主题。但是,您需要在旧订阅完成后用新订阅创建一个新主题,因此我创建了一个工厂函数来返回现有的可共享Observable(如果longObservable()
仍在进行中)或生成一个新主题一个。
以下是StackBlitz的重要内容:
let inProgress: boolean = false;
function longObservable(): Observable<string> {
return timer(5000).pipe(
map(() => randomString()),
tap(() => inProgress = false),
share()
)
}
let obs$: Observable<string>;
function getLongObs(): Observable<string> {
if (inProgress) {
return obs$
} else {
inProgress = true;
obs$ = longObservable();
return obs$;
}
}
console.log('initiate first subscribe');
getLongObs().subscribe(
rand => console.log(`First subscribe returned ${rand}`)
);
setTimeout(() => {
console.log('initiate second subscribe');
getLongObs().subscribe(
rand => console.log(`Second subscribe returned ${rand}`)
);
}, 2000);
setTimeout(() => {
console.log('initiate third subscribe');
getLongObs().subscribe(
rand => console.log(`Third subscribe returned ${rand}`)
);
}, 7000)
我希望这会有所帮助!
答案 1 :(得分:1)
如示例所示,您的方法将返回新的Observable实例,该实例在您每次订阅时都会创建。我认为在您的服务中您可以创建一个属性,该属性将存储您的可观察值。将此属性设置为BehaviorSubject可能更好。您也可以在任何地方订阅此属性。因此,每个订阅都将属于相同的Observable实例。
答案 2 :(得分:1)
我认为您想要的是share()
管道。像这样的作品:
export class AppComponent {
private _longObservable: Observable<string> = null
constructor() {
this._longObservable = timer(5000).pipe(
// This will show us when timer emits a value which will prove that the
// first two subscriptions below are sharing the same "execution"
// of the observable.
tap(() => console.log("Timer Triggered!")),
map(() => randomString()),
share()
);
}
ngOnInit() {
// These two will share the observable,
// since long observable hasn't completed by the time the second
// subscription is triggered.
this._longObservable.subscribe(console.log);
setTimeout(() => this._longObservable.subscribe(console.log), 2000);
// This subscription occurs after the 5 sec.
// Since timer is a cold observable, this will trigger it to run again.
setTimeout(() => this._longObservable.subscribe(console.log), 7000);
}
}
输出:
Timer Triggered!
randomString1
randomString1
Timer Triggered!
randomString2
如果您不熟悉这种区别,这里有一篇关于热和冷可观察物的区别的文章:https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339
Angular的Http请求和timer(5000)
都是冷观测对象。
此处是指向有关共享管道的一些信息的链接:https://www.learnrxjs.io/operators/multicasting/share.html