NgOnInit() 与构造函数并行运行 after/in
NgOnInit() Runs after/in parallel with constructor
constructor(private firestore: AngularFirestore, private activatedRoute: ActivatedRoute) {
this.firestore.collection('settings').doc('settings').valueChanges().subscribe(settings => {
console.log('getting settings');
this.settings = settings;
});
}
ngOnInit() {
this.activatedRoute.queryParams.subscribe(params => {
console.log(this.settings);
}
}
然而,我的控制台输出是
未定义
正在获取设置
我怎样才能让一个 运行 接一个?没有把所有的东西都放在 NgOnInit 中,整个代码都在 .then()
之后
编辑:
我已将代码编辑为下面建议的答案
使用 forkJoin:
ngOnInit() {
forkJoin([this.firestore.collection('settings').doc('settings').valueChanges(),
this.activatedRoute.queryParams]).subscribe(values => {
this.settings = values[0];
console.log('I am a console');
console.log(this.settings);
this.queryParams = values[1];
if (this.queryParams['myParam']) {
this.setmyParamTrue();
}
});
但是,无论有无任何 queryParams,都不会进入控制台
不用说,我只需要从 firestore 中检索设置一次,而且参数不必存在。
有两个运算符可以帮助您相互使用 2 个可观察对象:
- forkJoin
- 合并最新
- switchMap
如果你需要运行,一旦你有两个,使用forkJoin
如下:
constructor(
private firestore: AngularFirestore,
private activatedRoute: ActivatedRoute) {
forkJoin([
this.firestore.collection('settings').doc('settings').valueChanges(),
this.activatedRoute.queryParams
]).subscribe(values => {
this.settings = values[0]; //<- you'll get settings here
console.log(values[1]);
// use the call accordingly.
})
}
同样,如果需要连续收听,可以使用combineLatest
。并使用 switchMap
。完全取决于用例。
情况
来自您的原始代码:
1 class SomeComponent {
2
3 constructor(private firestore: AngularFirestore, private route: ActivatedRoute) {
4 this.firestore.collection().doc().valueChanges().subscribe(settings => {
5 console.log('getting settings');
6 this.settings = settings;
7 });
8 }
9
10 ngOnInit() {
11 this.route.queryParams.subscribe(params => {
12 console.log(this.settings);
13 }
14 }
15 }
在第 4 行的 constructor
中,您只是创建了一个 Subscription
。您传递给 .subscribe()
方法的逻辑将在每次 observable 发出值时执行。
在第 11 行的 ngOnInit
中,您正在创建另一个订阅。
回调函数的执行顺序完全取决于每个 observable 发出的时间,而不是您注册订阅的时间! (显然,在您的情况下,ActivatedRoute
的可观察值首先发射,然后是 AngularFireStore
的观察值。)
NgOnInit() Runs after/in parallel with constructor
希望你能明白为什么这个说法是不正确的!
目标
How can I make one run after the other?
您正尝试在回调中访问 this.settings
,但尚未准备好!解决方案是创建一个仅在 settings
值准备就绪后才开始的可观察对象。
让我们将您的设置定义为可观察对象:
1 class SomeComponent {
2
3 private settings$ = this.firestore.collection().doc().valueChanges();
4
5 constructor(private firestore: AngularFirestore, private route: ActivatedRoute) { }
6
7 ngOnInit() {
8 this.settings$.pipe(
9 switchMap(settings => this.route.queryParams.pipe(
10 tap(params => console.log('both values', { settings, params }))
11 ))
12 ).subscribe();
13 }
14 }
您在第 8 行看到我们从 this.setting$
和 pipe
开始到 switchMap
的排放,这将订阅内部源并发出源的排放。在这种情况下,您的内部源是可观察的参数。
我们将 pipe
放在可观察的内部参数上,这样 tap
就可以访问 settings
和发出的 params
.
tap
对于执行副作用很有用,通常比将逻辑放在订阅回调中更受欢迎。
根据您在 ngOnInit
中订阅的目的,单独定义可观察对象可能会有所帮助,就像我们在 settings$
:
中所做的那样
1 class SomeComponent {
2
3 private settings$ = this.firestore.collection().doc().valueChanges();
4 private doWork$ = this.settings$.pipe(
5 switchMap(settings => this.route.queryParams.pipe(
6 tap(params => console.log('both values', { settings, params }))
7 ))
8 );
9
10 constructor(private firestore: AngularFirestore, private route: ActivatedRoute) { }
11
12 ngOnInit() {
13 this.doWork$.subscribe();
14 }
15 }
constructor(private firestore: AngularFirestore, private activatedRoute: ActivatedRoute) {
this.firestore.collection('settings').doc('settings').valueChanges().subscribe(settings => {
console.log('getting settings');
this.settings = settings;
});
}
ngOnInit() {
this.activatedRoute.queryParams.subscribe(params => {
console.log(this.settings);
}
}
然而,我的控制台输出是
未定义
正在获取设置
我怎样才能让一个 运行 接一个?没有把所有的东西都放在 NgOnInit 中,整个代码都在 .then()
之后编辑: 我已将代码编辑为下面建议的答案
使用 forkJoin:
ngOnInit() {
forkJoin([this.firestore.collection('settings').doc('settings').valueChanges(),
this.activatedRoute.queryParams]).subscribe(values => {
this.settings = values[0];
console.log('I am a console');
console.log(this.settings);
this.queryParams = values[1];
if (this.queryParams['myParam']) {
this.setmyParamTrue();
}
});
但是,无论有无任何 queryParams,都不会进入控制台
不用说,我只需要从 firestore 中检索设置一次,而且参数不必存在。
有两个运算符可以帮助您相互使用 2 个可观察对象:
- forkJoin
- 合并最新
- switchMap
如果你需要运行,一旦你有两个,使用forkJoin
如下:
constructor(
private firestore: AngularFirestore,
private activatedRoute: ActivatedRoute) {
forkJoin([
this.firestore.collection('settings').doc('settings').valueChanges(),
this.activatedRoute.queryParams
]).subscribe(values => {
this.settings = values[0]; //<- you'll get settings here
console.log(values[1]);
// use the call accordingly.
})
}
同样,如果需要连续收听,可以使用combineLatest
。并使用 switchMap
。完全取决于用例。
情况
来自您的原始代码:
1 class SomeComponent {
2
3 constructor(private firestore: AngularFirestore, private route: ActivatedRoute) {
4 this.firestore.collection().doc().valueChanges().subscribe(settings => {
5 console.log('getting settings');
6 this.settings = settings;
7 });
8 }
9
10 ngOnInit() {
11 this.route.queryParams.subscribe(params => {
12 console.log(this.settings);
13 }
14 }
15 }
在第 4 行的 constructor
中,您只是创建了一个 Subscription
。您传递给 .subscribe()
方法的逻辑将在每次 observable 发出值时执行。
在第 11 行的 ngOnInit
中,您正在创建另一个订阅。
回调函数的执行顺序完全取决于每个 observable 发出的时间,而不是您注册订阅的时间! (显然,在您的情况下,ActivatedRoute
的可观察值首先发射,然后是 AngularFireStore
的观察值。)
NgOnInit() Runs after/in parallel with constructor
希望你能明白为什么这个说法是不正确的!
目标
How can I make one run after the other?
您正尝试在回调中访问 this.settings
,但尚未准备好!解决方案是创建一个仅在 settings
值准备就绪后才开始的可观察对象。
让我们将您的设置定义为可观察对象:
1 class SomeComponent {
2
3 private settings$ = this.firestore.collection().doc().valueChanges();
4
5 constructor(private firestore: AngularFirestore, private route: ActivatedRoute) { }
6
7 ngOnInit() {
8 this.settings$.pipe(
9 switchMap(settings => this.route.queryParams.pipe(
10 tap(params => console.log('both values', { settings, params }))
11 ))
12 ).subscribe();
13 }
14 }
您在第 8 行看到我们从 this.setting$
和 pipe
开始到 switchMap
的排放,这将订阅内部源并发出源的排放。在这种情况下,您的内部源是可观察的参数。
我们将 pipe
放在可观察的内部参数上,这样 tap
就可以访问 settings
和发出的 params
.
tap
对于执行副作用很有用,通常比将逻辑放在订阅回调中更受欢迎。
根据您在 ngOnInit
中订阅的目的,单独定义可观察对象可能会有所帮助,就像我们在 settings$
:
1 class SomeComponent {
2
3 private settings$ = this.firestore.collection().doc().valueChanges();
4 private doWork$ = this.settings$.pipe(
5 switchMap(settings => this.route.queryParams.pipe(
6 tap(params => console.log('both values', { settings, params }))
7 ))
8 );
9
10 constructor(private firestore: AngularFirestore, private route: ActivatedRoute) { }
11
12 ngOnInit() {
13 this.doWork$.subscribe();
14 }
15 }