如何避免 return promise 中的 observable
How to avoid to return an observable inside a promise
我正在使用 AngularFire 在我的应用程序中管理用户。我仍在学习 observables 和 rxjs。
我正在尝试调用 signInWithEmailAndPassword
方法 - return 一个承诺 - 并从集合中检索文档。
在我的服务中,我使用此方法获取文档:
getDbUser(uid): Observable<User> {
return this.angularFirestore.collection<User>(USERS).doc(uid).valueChanges()
}
我用以下方式登录用户:
login(user: User) {
// sign in con email e password
return this.angularFireAuth.signInWithEmailAndPassword(user.email, user.password)
.then((result) => {
if(result.user?.uid) {
// get user doc
return this.getDbUser(result.user.uid);
}
return null;
});
}
使用此代码,调用登录方法需要解决一个承诺,然后订阅可观察对象,如下所示:
this.userService.login(this.loginUser)
.then((userObs) => {
userObs.subscribe((user) => {
console.log(user);
});
})
我真的很想避免这种情况,但我不知道该怎么做。我尝试使用 RxJs toPromise
operator:
login(user: User) {
// sign in con email e password
return this.angularFireAuth.signInWithEmailAndPassword(user.email, user.password)
.then((result) => {
if(result.user?.uid) {
// recupero l'utente dal db
return this.getDbUser(result.user.uid).toPromise();
}
return null;
});
}
但不知何故这是行不通的(承诺从未得到解决)。
如果你想让任何可观察的消费者知道用户只是在 signInWithEmailAndPassword() 返回后才登录,我会标示一个主题并从任何服务消费者订阅 user$。
private userSubject$:Subject<string>=new Subject<string>();
public user$:Observable<string>=this.userSubject$.asObservable();
login(user: User) {
// sign in con email e password
return this.angularFireAuth.signInWithEmailAndPassword(user.email, user.password)
.then((result) => {
if(result.user?.uid) {
// recupero l'utente dal db
return this.userSubject$.next(result.user.uid);
}
return null;
});
}
从外部您将使用该服务:
this.userService.login(this.loginUser);
this.userService.user$.subscribe(user=>console.log);
第一条评论为正确答案:
You can add .pipe(first())
before .toPromise
"
toPromise() 不起作用的原因是 observable 保持打开状态。使用 first 运算符,或者如果您使用的是更高版本的 rxjs,则使用 firstValueFrom。在 Conversion to Promises 从 rxjs 文档中阅读更多相关信息。
由于您使用的是 valuesChanges 而不是 get,那么您的意图可能是保持 observable 打开。如果是这种情况,那么最好的办法是使用 from.
将登录名转换为可观察的
login(user: User) {
return from(this.angularFireAuth.signInWithEmailAndPassword(user.email, user.password)).pipe(
switchMap(res => (res.user.uid)
? this.getDbuser(res.user.uid)
: of(null))
);
}
我正在使用 AngularFire 在我的应用程序中管理用户。我仍在学习 observables 和 rxjs。
我正在尝试调用 signInWithEmailAndPassword
方法 - return 一个承诺 - 并从集合中检索文档。
在我的服务中,我使用此方法获取文档:
getDbUser(uid): Observable<User> {
return this.angularFirestore.collection<User>(USERS).doc(uid).valueChanges()
}
我用以下方式登录用户:
login(user: User) {
// sign in con email e password
return this.angularFireAuth.signInWithEmailAndPassword(user.email, user.password)
.then((result) => {
if(result.user?.uid) {
// get user doc
return this.getDbUser(result.user.uid);
}
return null;
});
}
使用此代码,调用登录方法需要解决一个承诺,然后订阅可观察对象,如下所示:
this.userService.login(this.loginUser)
.then((userObs) => {
userObs.subscribe((user) => {
console.log(user);
});
})
我真的很想避免这种情况,但我不知道该怎么做。我尝试使用 RxJs toPromise
operator:
login(user: User) {
// sign in con email e password
return this.angularFireAuth.signInWithEmailAndPassword(user.email, user.password)
.then((result) => {
if(result.user?.uid) {
// recupero l'utente dal db
return this.getDbUser(result.user.uid).toPromise();
}
return null;
});
}
但不知何故这是行不通的(承诺从未得到解决)。
如果你想让任何可观察的消费者知道用户只是在 signInWithEmailAndPassword() 返回后才登录,我会标示一个主题并从任何服务消费者订阅 user$。
private userSubject$:Subject<string>=new Subject<string>();
public user$:Observable<string>=this.userSubject$.asObservable();
login(user: User) {
// sign in con email e password
return this.angularFireAuth.signInWithEmailAndPassword(user.email, user.password)
.then((result) => {
if(result.user?.uid) {
// recupero l'utente dal db
return this.userSubject$.next(result.user.uid);
}
return null;
});
} 从外部您将使用该服务:
this.userService.login(this.loginUser);
this.userService.user$.subscribe(user=>console.log);
第一条评论为正确答案:
You can add
.pipe(first())
before.toPromise
"
toPromise() 不起作用的原因是 observable 保持打开状态。使用 first 运算符,或者如果您使用的是更高版本的 rxjs,则使用 firstValueFrom。在 Conversion to Promises 从 rxjs 文档中阅读更多相关信息。
由于您使用的是 valuesChanges 而不是 get,那么您的意图可能是保持 observable 打开。如果是这种情况,那么最好的办法是使用 from.
将登录名转换为可观察的login(user: User) {
return from(this.angularFireAuth.signInWithEmailAndPassword(user.email, user.password)).pipe(
switchMap(res => (res.user.uid)
? this.getDbuser(res.user.uid)
: of(null))
);
}