我有一个移动应用程序我正在构建,现在我正在进行身份验证。在我访问主页之前,我需要在我可以向用户显示数据之前构建的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);
});
}
答案 0 :(得分:15)
您的原始代码存在导致此错误的错误。您的代码中有三个调用,我将其称为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的是冷 Observable(代表启动异步操作所需的所有信息)与 hot <之间的区别/ strong> Observable(具有异步操作的Observable已经启动)。
三个调用A),B)和C)仅构建冷可观察对象,这些可观察对象在你对它们调用.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 :(得分:0)
这应该有效。不要忘记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());
})