我有一个服务(data.service.ts)和一个组件(page.component.ts)。
在此data.service.ts服务中,有一个名为changes$
的可观察对象
当我加载页面时,它成功地从存储中获取了数据并将其解析(使用.next())到可观察对象。
在我的page.component.ts组件中,它已订阅此可观察的内容,以下每一项更改均得到处理,但第一个(页面加载时)没有得到处理。
为什么?我的data.service.ts在将page.component.ts订阅到此changes$
可观察对象之前,解析了数据(使用.next())。
“等待”直到订阅该组件的最佳方法是什么?
我找到了使用setTimeout(() => { ... }, 0)
的解决方法,但感觉不对(如果您知道我的意思)
以下是一些代码:
data.service.ts:
export class DoorService implements OnDestroy {
private data: DoorServiceData;
private destroy$: Subject<void> = new Subject();
private changesSubject$: Subject<IDoorSettings> = new Subject();
// this way users cannot parse values to the subject. read-only...
public changes$: Observable<IDoorSettings> = this.changesSubject$.asObservable().pipe(takeUntil(this.destroy$));
constructor(){
this.init();
}
// service initializer, set data etc.
private init() {
setTimeout(() => {
let savedData: DoorServiceData = this.getFromStorage();
if(!savedData)
{
savedData = {settings: {usedInStore: false, isValid: false}};
}
this.data = savedData;
this.changesSubject$.next(this.data.settings);
console.log("DOOR SERVICE DATA SET");
}, 0)
}
}
page.component.ts:
export class SearchComponent implements OnInit{
public settings: IDoorSettings;
constructor(public doorService: DoorService) {}
ngOnInit(): void {
this.watchSettings();
}
private watchSettings() {
console.log("Watching settings");
this.doorService.changes$.subscribe((val) => {
this.settings = val;
});
}
}
使用chrome控制台,我可以告诉它在订阅组件之前解析数据(当我不使用“ setTimeout”解决方法时)
处理这种情况的最佳方法是什么?
我也尝试过async
管道,但是没有运气。
谢谢。
答案 0 :(得分:2)
您应该代替BehaviourSubject或ReplaySubject。
“等待”直到订阅该组件的最佳方法是什么?
先生,在RxJS世界中,这是一个令人恐惧的想法。就像广播电台应该等待播放歌曲,直到至少有一个收听者收听为止。
以广播电台为例,您要告诉我的是,一旦收听,第一首歌曲就消失了,因此您添加了BehaviourSubject或ReplaySubject。
BehaviorSubject具有存储“当前”值的特征。这意味着您始终可以直接从BehaviorSubject获得最后发出的值。因此,一旦您收听广播,就会播放最后播放的歌曲。
const subject = new Rx.BehaviorSubject(Math.random());
// subscriber 1
subject.subscribe((data) => {
console.log('Subscriber A:', data);
});
// output
// Subscriber A: 0.24957144215097515
ReplaySubject与BehaviorSubject在可向新订户发送“旧”值的方式上具有可比性。但是,它还有一个额外的特性,它可以记录一部分可观察到的执行,因此可以存储多个旧值并将它们“重播”给新的订户。 创建ReplaySubject时,您可以指定要存储多少值以及要存储多长时间。换句话说,您可以指定:“我要存储最近2个值,这些值是在新订阅之前的最近100毫秒中执行的。”
const subject = new Rx.ReplaySubject(2, 100);
// subscriber 1
subject.subscribe((data) => {
console.log('Subscriber A:', data);
});
setInterval(() => subject.next(Math.random()), 200);
// subscriber 2
setTimeout(() => {
subject.subscribe((data) => {
console.log('Subscriber B:', data);
});
}, 1000)
// Subscriber A: 0.44524184251927656
// Subscriber A: 0.5802631630066313
// Subscriber A: 0.9792165506699135
// Subscriber A: 0.3239616040117268
// Subscriber A: 0.6845077617520203
// Subscriber B: 0.6845077617520203
// Subscriber A: 0.41269171141525707
// Subscriber B: 0.41269171141525707
// Subscriber A: 0.8211466186035139
// Subscriber B: 0.8211466186035139
答案 1 :(得分:0)
尝试RepleySubject而不是Subject
private changesSubject$: ReplaySubject<IDoorSettings> = new ReplaySubject(1);