我有一个与Firestore后端通信的Angular 7应用程序。
由于异步处理,我仍然想将Promise vs Observables笼罩着。
请考虑以下情形。在加载页面时,我需要先检查一些用户权限,然后才能确定它可以显示给我们什么。
由于权限是动态的,并且基本上是页面级别的,因此我们需要获取当前页面的Firestore条目,获取登录的Firestore用户,我分别存储的扩展用户信息,权限名称Im寻找,最后,我可以检查页面用户权限中是否存在用户权限。
是的,我可能应该对数据进行非规范化。
但是您可以从中看到Im必须具有多个查询级别,在显示数据之前,我需要首先运行该查询,并且Im确实要厌倦所有嵌套的Observable订阅。
checkGroupPermission(groupId: string, permissionName: string): any {
this.userService.getCurrentUser().then(user => {
this.userService.getUserForFirebaseUid(user.uid).subscribe(users => {
if (users.length === 0) { return false; }
this.groupUsersService.getAllForUser(users[0].id).subscribe(groupUsers => {
const groupUser = groupUsers.find(cu => cu.groupId === groupId);
this.roleService.getRole(groupUser.roleId).subscribe(role => {
this.rolePermissionService.getRolePermissionsForRoleId(role.id).subscribe(rolePermissions => {
this.permissionService.getPermissionByName(permissionName).subscribe(permissions => {
if (permissions.length === 0) { return false; }
const rolePermission = rolePermissions.find(rp => rp.permissionId === permissions[0].id);
if (rolePermission) {
return true;
} else {
return false;
}
});
});
});
});
});
});
}
我还拥有大约五个不同的权限来检查。我想整理一下,然后看一下Promises vs Observables。
checkSomething(): Promise<boolean> {
return this.myService.getData().then(data => {
return true;
}, reason => {
return false;
});
}
subCheckOfSomething(): Observable<boolean> {
return this.myService.getFirebaseSubscribe().pipe(map(dataArray => {
if (dataArray.length > 0) {
return true;
} else {
return false;
}
}));
}
分别使用这两个函数是可以的,但是如果我尝试从另一个函数调用另一个函数:
checkSomething(): Promise<boolean> {
return this.myService.getData().then(data => {
this.subCheckOfSomething().subscribe(data => { return data; });
}, reason => {
return false;
});
}
不起作用,因为可观察对象不是承诺
我知道我可以重写subCheckOfSomething来返回一个Promise:
subCheckOfSomething(): Promise<boolean> {
return new Promise(resolve,reject) => {
const data = this.myService.getFirebaseSubscribe().pipe(map(dataArray => {
if (dataArray.length > 0) {
return true;
} else {
return false;
}
}));
data.subscribe(result => {
resolve(result);
}, err => {
reject(err); })
});
}
但这并不是最好的解决方案。有没有首选的方式来处理这种情况?
答案 0 :(得分:1)
使用承诺
RxJs有一个toPromise
方法,您可以用它来返回一个Promise。一旦可观察者完成,诺言将解析为可观察者的最后发射值。
subCheckOfSomething(): Promise<boolean> {
return this.myService.getFirebaseSubscribe().pipe(map(dataArray => {
if (dataArray.length > 0) {
return true;
} else {
return false;
}
}))
.toPromise();
}
使用观测值
问题是您不能及早打破可观察的链(您可以进行破解并抛出错误并在最后捕获该错误,但是我认为不建议这样做),因此您拥有这些嵌套的可观察订阅。正如您提到的,您应该将其整理成几种方法。您也只需要在最后订阅一次即可,就可以像这样通过管道传递其余方法:
checkGroupPermission(groupId: string, permissionName: string): Observable<boolean> {
this.userService.getCurrentUser().pipe(
switchMap(user => {
this.userService.getUserForFirebaseUid(user.uid).pipe(
switchMap(users =>
if (users.length === 0) { return of(false); }
return this.groupUsersService.getAllForUser(users[0].id).pipe(
switchMap(groupUsers => {
// Basically you replace subscribe with pipe(switchMap())
})
})
);
}
我个人认为在您的应用程序的某些部分中做出承诺是可以的。对于我来说,async
/ await
(不使用.then
)似乎最容易理解,只要您不需要其他功能,例如“中止此检查并开始一个新的”(switchMap对此非常有用),我会满意的。此外,您可以使用toPromise
(rxjs-> promise)或静态rxjs-operator from
(promise-> rxjs)轻松地将彼此转移。