如果我有一个需要很长时间才能执行的可观察对象。我们将其称为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
完成,它将立即发出与其他两个相同的值。
这用于设备上的地理定位。我想请求一个新位置,但如果已经有一个请求正在进行中,则只需使用该结果。
编辑:将 observable 更改为多播主题,删除 take(1)。
编辑2:https://stackblitz.com/edit/angular-venpk4这是我想要的一个工作示例。我希望在没有timerRunning 变量和RxJS 运算符的情况下完成此任务。它位于 hello 组件下并打印到控制台。
最佳答案
棘手的问题。这是我在 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)
希望这会有所帮助!
关于angular - 如果可观察对象正在进行中,则订阅它,如果没有,则重新启动它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54136646/