Angular 2调用多个异步方法

Jas*_*son 7 javascript rxjs typescript angular

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

Joh*_*lph 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)
Run Code Online (Sandbox Code Playgroud)

关于RXJS需要了解的是 Observable(表示启动异步操作所需的所有信息)和hot 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);
    });
Run Code Online (Sandbox Code Playgroud)

关于rxjs的好处是错误处理只能在Observable链中一直工作.如果您可以并行执行C),请查看.forkJoin().

最后,如果你需要亲自解释.mergeMap()看看这个答案:在#ngrx示例中的SwitchMap与MergeMap