我正在构建一个带有登录/注册流程的angular应用程序,并且我正在寻找一种简单且更易读的方式来编写以下代码:
register() {
this.accountService.register(this.user, this.password, this.passwordConfirmation).subscribe(() => {
this.accountService.login(this.user.email, this.password).subscribe((loginResult) => {
this.accountService.csrfRefresh().subscribe(() => {
if (loginResult.status === ELoginStatus.success) {
this.router.navigateByUrl(this.returnUrl);
} else {
this.errorMessage$.next('Login unsuccessful');
}
}, () => {
this.errorMessage$.next('Login unsuccessful');
})
}, () => {
this.errorMessage$.next('Login unsuccessful');
})
}, () => {
this.errorMessage$.next('Login unsuccessful');
});
}
使用此代码,我需要编写4次错误处理代码,或创建一个单独的方法,或将数据传递给BehaviorSubject
。这看起来太慢了。
我一直在考虑使用await
:
async register() {
try {
await this.accountService.register(this.user, this.password, this.passwordConfirmation).toPromise();
const loginResult = await this.accountService.login(this.user.email, this.password).toPromise();
await this.accountService.csrfRefresh().toPromise();
// TS2532: Object is possibly 'undefined'
if (loginResult!.status === ELoginStatus.success) {
this.router.navigateByUrl(this.returnUrl);
} else {
this.errorMessage$.next('Login unsuccessful');
}
} catch (exception) {
this.errorMessage$.next('Login unsuccessful');
}
}
这样好多了,但是我希望避免使用async/await
,并且需要在可观察对象上使用.toPromise()
。
链接这3个api调用的推荐方法是什么?
您应该能够以一种更习惯的rxjs方式重写此逻辑,如下所示
register() {
this.accountService.register(this.user, this.password, this.passwordConfirmation).pipe(
concatMap(() => this.accountService.login(this.user.email, this.password)),
concatMap((loginResult) => {
if (loginResult.status === ELoginStatus.success) {
return this.router.navigateByUrl(this.returnUrl)
}
throw new Error("Login unsuccessful")
})
)
.subscribe({
next: data => {
// process any result in case of success
},
error: () => this.errorMessage$.next('Login unsuccessful')
})
}
正如你所看到的,当我需要编写多个http调用时,我倾向于使用concatMap
,因为concatMap
意味着我们在移动到第二个调用之前等待前一个调用的响应。
switchMap
是正确的操作符,如果我们想在新请求进入时"杀死动态请求"。
mergeMap
应该当你想使用并行管理更多的请求,但它有自己的复杂性。
也许你能在这里找到一些灵感。