Angular 2调用多个异步方法
Posted
技术标签:
【中文标题】Angular 2调用多个异步方法【英文标题】:Angular 2 calling multiple async methods 【发布时间】:2017-08-08 01:21:12 【问题描述】:我正在构建一个移动应用程序,现在我正在处理身份验证。在我点击我的主页之前,我需要在我构建的 API 上点击各种端点,然后才能向用户显示数据。
在 Postman 中测试时,所有端点都返回了正确的数据,但是当我在我的应用程序中使用它时,我在第二次异步调用中得到了一个 null
值。
我确信这与进行这些调用的顺序有关,因此我只是在寻求一些帮助,以了解如何在开始另一个调用之前正确等待一个调用完成。
public login()
this.showLoading();
this.userService.getUserIdFromUserName(this.registerCredentials.username) // WORKS
.subscribe(
res =>
console.log(res);
localStorage.setItem("UserId", res.toString());
,
err =>
console.log(err);
);
this.userService.getEmployeeIdFromUserId(localStorage.getItem("UserId")) // THIS RETURNS NULL
.subscribe(
res =>
console.log(res);
localStorage.setItem("EmployeeId", res.toString());
,
err =>
console.log(err);
);
this.authService.login(this.registerCredentials)
.subscribe(
data =>
this.loading.dismissAll();
console.log('User logged in successfully! ', data);
this.nav.push(TabsPage);
localStorage.setItem("Username", this.registerCredentials.username);
localStorage.setItem("isLoggedIn", "true");
,
error =>
this.loading.dismissAll();
this.showAlert("Uh oh!", "Something went wrong. Please re-enter your login credentials or check your connection.");
console.log(error);
);
【问题讨论】:
标题为Angular2
,但关键字为angularjs
。您可以考虑修改两者之一。
你应该在this answer找到你需要的东西。
【参考方案1】:
您的原始代码存在导致此错误的错误。您的代码中有三个调用,我将它们称为 A)、B) 和 C):
A) this.userService.getUserIdFromUserName(this.registerCredentials.username) // WORKS
B) this.userService.getEmployeeIdFromUserId(localStorage.getItem("UserId")) // THIS RETURNS NULL
C) this.authService.login(this.registerCredentials)
关于 RXJS,您需要了解的是 cold Observable(代表启动异步操作所需的所有信息)和 hot Observable(这是一个异步操作已经开始的 Observable)。
这三个调用 A)、B) 和 C) 只是构建冷的 observables,它们在你调用 .subscribe()
的那一刻就开始了。因此,当 B) 建成时,A) 已经开始但尚未完成。因此对localStorage.getItem("UserId")
的调用将返回null,因为A) 尚未调用其订阅者的next
回调。
所以你想要做的是让 B) 等待 A)。此外,与其将某些东西填充到全局状态(localStorage)中,不如将结果从 A)流向 B)。输入.mergeMap()
运算符:
this.userService.getUserIdFromUserName(this.registerCredentials.username) // WORKS
.map(res => res.toString())
.do(userId => localStorage.setItem("UserId", userId)) // cleanly separate side-effects into .do() calls
.mergeMap(userId => this.userService.getEmployeeIdFromUserId(userId))
.map(res => res.toString())
.do(employeeId => localStorage.setItem("EmployeeId", employeeId))
.subscribe(
employeeId =>
console.log(employeeId);
,
err =>
console.log(err);
);
关于 rxjs 的好处是错误处理可以一直通过 Observable 链进行。
如果您可以并行执行 C),请查看 .forkJoin()
.
最后,如果您需要对 .mergeMap()
的解释,请查看以下答案:SwitchMap vs MergeMap in the #ngrx example
【讨论】:
+1:很好的答案。这里真的很容易理解并且整体非常干净的代码。显然这与你无关,但我希望 RxJS 操作符有更好的名字。人们想摆脱selectMany
(这是一个好名字),所以他们选择了flatMap
(这也是一个好名字)。两者都保留了与集合的类比。 mergeMap
什么都不做。它可能在排序方面更具描述性,或者缺少它们,但读起来像是故意提供直觉,但它却惨遭失败。他们不妨将其重命名为 bind
并完成它。
问题:switchmap 不是更好的解决方案吗? (我知道区别,但仍然......)【参考方案2】:
这应该有效。不要忘记import 'rxjs/Rx'
this.userService.getUserIdFromUserName(this.registerCredentials.username)
.map(res => res.toString())
.do(userId =>
console.log(res);
localStorage.setItem("UserId", userId);
)
.flatMap(userId =>
return this.userService.getEmployeeIdFromUserId(userId);
)
.do(res =>
console.log(res);
localStorage.setItem("EmployeeId", res.toString());
)
【讨论】:
以上是关于Angular 2调用多个异步方法的主要内容,如果未能解决你的问题,请参考以下文章