Angular 2调用多个异步方法

时间:2017-03-16 17:47:40

标签: javascript angular typescript rxjs

我有一个移动应用程序我正在构建,现在我正在进行身份验证。在我访问主页之前,我需要在我可以向用户显示数据之前构建的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);
    });
  }

2 个答案:

答案 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());
    })