Joe*_*Joe 3 rxjs typescript angular
在我的 Angular 应用程序中,我正在进行可选的 HTTP 调用来检查用户是否存在。根据这次通话的结果,我要么想再拨打一次电话,要么停止处理。如果不求助于.toPromise(),我如何等待在块中进行的调用if?
onSomeEvent() {
const contact: IContact = {
...this.userForm.value
};
let cancelProcessing = false;
if (this.isNewUser()) {
// *** This is optional
this.userService.duplicateUserSearch(contact.email, contact.userName)
.subscribe(result => {
if (result.result !== '') {
cancelProcessing = true;
}
});
}
// *** This statement is hit before the observable completes
if (cancelProcessing) {
return;
}
// *** which means that this runs when it shouldn't
this.userService.updateContact(contact)
.subscribe(res => {
this.activeModal.close(res);
});
}
Run Code Online (Sandbox Code Playgroud)
正如您在问题中所展示的,如果/那么 Observables 的逻辑可能很棘手。这里有一个关于这个的很好的讨论。
你已经有了一些在某些条件下可行的答案,我会直接离开,把你留给范或杰弗里的有能力的人,但我对你对一个答案的评论很感兴趣:“如果我添加更多条件吗?”。这引起了我的兴趣,因此我想找到一种基于可观察/函数的模式,易于阅读,并且如果您稍后决定添加其他条件,则可以轻松扩展。一个好问题让我认真思考,你确实做到了。:)
我尝试应用上面链接的文章中建议的模式来解决您的问题,下面的代码是我想出的。正如我在上面对您原来问题的评论中提到的,我不能 100% 确定您打算在用户不是新用户时更新联系人,但现在我假设您这样做。免责声明:我还没有对此进行严格的测试,例如创建 Stackblitz 和创建各种测试用例,尽管这是我通常想要回答这样的问题的方式,所以我对下面代码中的任何错误或意外后果表示歉意。唉,周末来了。;)
在本文的模式中,建议通过 if/then 逻辑为所有可能的路径创建分支。我提出了两个主要分支,这两个分支将导致 updateContact() 被调用。请注意,使用此模式可以轻松地tap()在任何分支中添加 a 以在需要时执行其他工作。如果我错过了您想要添加的分支,也应该很容易添加。
这个模式的核心是最后的 merge() 。这将创建一个合并传入的两个可观察量的单个可观察量。如果其中任何一个完成,则订阅将执行并运行updateContact()。在这种情况下,它们永远不会同时完成,因为过滤器保证isNewUser()只有一个会处于活动状态,但如果您在其他地方应用此模式,如果您只关心第一个“获胜”的异步模式,则可能需要添加 a take(1)。
我还显示了订阅和取消订阅,因为我认为这是最佳实践。
onSomeEventSub : Subscription; // component scope variable to add to later unsubscribe with
onSomeEvent() {
const contact: IContact = {
...this.userForm.value
};
// define duplicateUserSearch$ now for easier readability below
const duplicateUserSearch$: Observable<boolean> =
this.userService.duplicateUserSearch(contact.email, contact.userName).pipe(
map(result => (result.result === '')));
// First, create a shareable source for eventual merge of all branches.
// of(0) is completely arbitrary. It would be more interesting to tie
// this to the original event, but that wasn't part of the question. :)
const source$ = of(0).pipe(
share() // same observable will have multiple observers
);
// branch 1 is for when the user is a new user and duplicate logic asserts
const isNewUserAndIsDupe$ = source$.pipe(
filter(() => isNewUser()),
mergeMap(() => duplicateUserSearch$),
filter(res => res)
);
// branch 2 is when the user is NOT a new user
const isNotNewUser$ = source$.pipe(
filter(() => !isNewUser())
);
// and finally the merge that pulls this all together and subscribes
this.onSomeEventSub = merge(isNewUserAndIsDupe$, isNotNewUser$).pipe(
mergeMap(() => this.userService.updateContact(contact))
).subscribe(res => this.activeModal.close(res));
}
ngOnDestroy() {
if (this.onSomeEventSub) this.onSomeEventSub.unsubscribe();
}
Run Code Online (Sandbox Code Playgroud)