Angular 7:为什么我必须调用我的subscribe方法两次才能生效

Angular 7:为什么我必须调用我的subscribe方法两次才能生效,angular,scope,rxjs,angular2-observables,subscribe,Angular,Scope,Rxjs,Angular2 Observables,Subscribe,我认为我误解了订阅和观测,我不觉得角度文档特别有用 我正在创建一个validationService,用于检查用户名是否可用。表单提交时调用validationService,如果用户名不可用,则会显示错误消息。问题是,我必须提交两次表格才能生效 validationService对后端进行http调用,返回布尔值。我有一个局部变量“availableUsername”,我想将结果设置为,以便在其他地方使用它。在subscribe函数中,它工作正常,我得到结果并将其设置为这个变量。但是当我离开s

我认为我误解了订阅和观测,我不觉得角度文档特别有用

我正在创建一个validationService,用于检查用户名是否可用。表单提交时调用validationService,如果用户名不可用,则会显示错误消息。问题是,我必须提交两次表格才能生效

validationService对后端进行http调用,返回布尔值。我有一个局部变量“availableUsername”,我想将结果设置为,以便在其他地方使用它。在subscribe函数中,它工作正常,我得到结果并将其设置为这个变量。但是当我离开subscribe方法的作用域时,变量是未定义的。但当我再次调用submit时,它就起作用了

我在下面添加了validationService和userService

validationService.ts

import { Injectable } from '@angular/core';
import { FormControl } from '@angular/forms';

import { AlertService } from './../services/alert.service';
import { UserService } from './../services/user.service';

@Injectable({
  providedIn: 'root'
})
export class ValidationService {

  availableUsername: boolean;
  availableEmail: boolean;

  constructor(
    private alertService: AlertService,
    private userService: UserService
    ) { }

  validateUsername(controls: any): boolean {

    const username = controls.username.value;

    this.isUsernameAvailable(username);

    if (!this.availableUsername) {
      this.alertService.error('This username is already taken', false);
      return true;
    }
    return false;
  }

  private isUsernameAvailable(username: string) {

    if (username === undefined || username === '') {
      return;
    }

    this.userService.isUserNameAvailable(username)
      .subscribe((result) => {
        this.availableUsername = result;
    },
    error => {
      this.alertService.error(error);
      return;
    });
  }

}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { environment } from './../../environments/environment';

@Injectable({ providedIn: 'root' })
export class UserService {

  apiUrl: string = environment.apiUrl;

  constructor(private http: HttpClient) { }

  isUserNameAvailable(username: string) {
    return this.http.get<boolean>(`${this.apiUrl}/users/checkUsernameAvailability/${username}`);
  }

}
userService.ts

import { Injectable } from '@angular/core';
import { FormControl } from '@angular/forms';

import { AlertService } from './../services/alert.service';
import { UserService } from './../services/user.service';

@Injectable({
  providedIn: 'root'
})
export class ValidationService {

  availableUsername: boolean;
  availableEmail: boolean;

  constructor(
    private alertService: AlertService,
    private userService: UserService
    ) { }

  validateUsername(controls: any): boolean {

    const username = controls.username.value;

    this.isUsernameAvailable(username);

    if (!this.availableUsername) {
      this.alertService.error('This username is already taken', false);
      return true;
    }
    return false;
  }

  private isUsernameAvailable(username: string) {

    if (username === undefined || username === '') {
      return;
    }

    this.userService.isUserNameAvailable(username)
      .subscribe((result) => {
        this.availableUsername = result;
    },
    error => {
      this.alertService.error(error);
      return;
    });
  }

}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { environment } from './../../environments/environment';

@Injectable({ providedIn: 'root' })
export class UserService {

  apiUrl: string = environment.apiUrl;

  constructor(private http: HttpClient) { }

  isUserNameAvailable(username: string) {
    return this.http.get<boolean>(`${this.apiUrl}/users/checkUsernameAvailability/${username}`);
  }

}
从'@angular/core'导入{Injectable};
从'@angular/common/http'导入{HttpClient};
从“/../../environments/environment”导入{environment};
@可注射({providedIn:'root'})
导出类用户服务{
apiUrl:string=environment.apiUrl;
构造函数(私有http:HttpClient){}
IsUserName可用(用户名:字符串){
返回this.http.get(`${this.apirl}/users/checkUsernameAvailability/${username}`);
}
}

代码中的问题是您试图使用异步同步 只有在调用
subscribe
回调时,才会设置
availableUsername
属性值,这将在
if(!this.availableUsername)
之后很久

在这种情况下,您可以使用为这些情况构建的

另一种(不太推荐的)替代方法是使用
async
wait
同步运行代码

this.isUsernameAvailable(username); 
当执行上述这行代码时,它将异步运行,因此在为
this.availableUsername=result赋值之前
通过订阅,将运行以下代码

 if (!this.availableUsername) {
      this.alertService.error('This username is already taken', false);
      return true;
    }
    return false;
  }
为了避免这种情况,我们需要做的是像这样检查订阅中的这个条件

     this.userService.isUserNameAvailable(username)
          .subscribe((result) => {
            this.availableUsername = result;
        },
        error => {
          this.alertService.error(error);
          return;
        }
         ()=>{
 if (!this.availableUsername) {
      this.alertService.error('This username is already taken', false);

    }
}
);
      }

    }

AJAX中的A表示异步。传递给subscribe()的函数初始化this.availableUsername
,在验证器返回其结果后立即执行。您需要使用异步验证器。但最重要的是,您需要了解异步的原理。所以validateUsername不是在等待IsUserName完成吗?是的,它是在等待。正如您所看到的,isUsername不会返回任何内容。它所做的只是发送一个http请求并立即返回。此时,isUsernameAvailable()已完成。但是,对请求的响应将在很久以后由回调处理。就像,如果我告诉你“请为我烤一片面包”,你将在2秒钟内完成这项任务:将面包放入烤面包机所需的时间。不过,我要等很久才能吃到吐司:当烤面包机响起来通知我吐司准备好了。当烤面包机慢慢地烤面包的时候,你和我做了很多其他的事情。