gpt4 book ai didi

javascript - 路由解析器在没有订阅的情况下不会触发可观察的

转载 作者:行者123 更新时间:2023-11-30 20:32:56 31 4
gpt4 key购买 nike

我有一条路线,在路线加载之前需要来 self 的 Firebase 数据库的一些数据。感觉路由没有调用订阅,所以请求永远不会被触发。我错过了一步吗?

( Angular 5)

我的路由器:

{
path: 'class/:idName',
component: ClassComponent,
resolve: {
classData: ClassResolver
}
},

我的解析器:

@Injectable()
export class ClassResolver implements Resolve<any> {

constructor(
private db: AngularFireDatabase
) {}

resolve(route: ActivatedRouteSnapshot): Observable<any> | Promise<any> | any {
// return 'some data'; //This worked fine
return this.db
.list('/')
.valueChanges() // Returns Observable, I confirmed this.
//.subscribe(); // This returns a Subscriber object if I call it and I never get any data
}

// I tried this and it didnt work either
//const list = this.db
// .list('/')
// .valueChanges();
//console.log('list', list); // Is a Observable
//list.subscribe(data => {
// console.log('data', data); // returned data
// return data;
//});
//return list; // never gets to the component
}

我的组件:

public idName: string;
// Other vars

constructor(
private fb: FormBuilder,
private route: ActivatedRoute,
private db: AngularFireDatabase
) {
// Form stuff
}

ngOnInit() {
// Never makes it here
this.idName = this.route.snapshot.params.idName;
const myclass = this.route.snapshot.data.classData;
console.log('myclass', myclass);
}

我从来没有进入组件。它等待组件加载,但它从不加载。如果我添加 subscribe 和 console.out 数据,它会很快返回正确的数据,所以它不是服务。


在我的 Resolver 中调用 .subscribe() 之后,它现在返回一个 Subscriber 对象。因为我的返回签名允许 any 它返回这个 Subscriber 就好像它是数据一样。现在这似乎很明显。

我的问题现在变成了为什么它不解析我的 Observable

最佳答案

您的resolve 函数正在返回一个永远不会完成 的Observable。 Observable 确实在触发(这可以通过在它的管道中添加一个 tap 和一些控制台日志记录来验证)——但是解析阶段不会结束(因此你的组件不会加载)直到 Observable 完成。 (文档不太擅长强调这一点。)

显然你也不希望你的 Observable 完成,因为那样你就不会得到进一步的数据更新。

最简单的“修复”是将 Observable 包装在 Promise 中:

async resolve(route: ActivatedRouteSnapshot): Promise<Observable<any>> {
return this.db.list('/').valueChanges();
}

但这并不能保证 Firebase 已发出其初始响应,我认为这是您在路由加载之前要确保的。

我能看到的唯一方法是:

  1. 确保在 Firebase 至少返回一次数据之前不会加载该组件;和
  2. 防止一次有效操作发生两次不同的 Firebase 读取(一次由解析器读取,另一次由组件读取)

是将您的 Firebase Observable 包装在一个服务中:

import { Injectable, OnDestroy, OnInit } from '@angular/core';
import { AngularFireDatabase } from '@angular/fire/database';
import { Subscription } from 'rxjs';
import { shareReplay } from 'rxjs/operators';

@Injectable({
providedIn: 'root',
})
export class DataService implements OnInit, OnDestroy {
constructor(private readonly db: AngularFireDatabase) {}

/**
* Observable to the data.
* shareReplay so that multiple listeners don't trigger multiple reads.
*/
public readonly data$ = this.db
.list('/')
.valueChanges()
.pipe(shareReplay({ bufferSize: 1, refCount: true }));

/**
* To trigger the first read as soon as the service is initialised,
* and to keep the subscription active for the life of the service
* (so that as components come and go, multiple reads aren't triggered).
*/
private subscription?: Subscription;

ngOnInit(): void {
this.subscription = this.data$.subscribe();
}
ngOnDestroy(): void {
this.subscription?.unsubscribe();
}
}

然后您的解析器将如下所示:

async resolve(route: ActivatedRouteSnapshot): Promise<Observable<any>> {
// ensure at least one emission has occurred
await this.dataService.data$.pipe(take(1)).toPromise();

// ...then permit the route to load
return this.dataService.data$;
}

通过将您的 Firebase Observable 包装在服务中,您可以获得 OnInitOnDestroy 生命周期 Hook ,您可以使用它们来确保 observable 在组件加载之间“继续存在” (并防止在一个就足够的情况下进行多次 Firebase 读取)。因为数据随后会被挂起,所以后续数据加载也会更快。最后,这仍然使您能够使用解析器来确保数据在继续加载组件之前立即可用。

关于javascript - 路由解析器在没有订阅的情况下不会触发可观察的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50144332/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com