Возвращаемое значение с асинхронными функциями в Typescript - PullRequest
0 голосов
/ 04 июля 2018

У меня есть следующая функция TS:

CheckRegUser(u: User): boolean {
    let b: boolean = true;
    let toSend = {
      email: u.email
    };
    this.http.post("http://localhost:8080/", toSend).subscribe((data: Valid) => {
      if(!data.validity){
        b = false;
      }
    });
    console.log(b);
    return b;
}

Здесь я подключаюсь к бэкэнду ExpressJS и получаю логический результат. Эта часть работает нормально, но проблема в том, что оператор return b выполняется перед тем, как значение b изменяется в "this.http", поэтому b всегда истинно независимо от ответа Express.

Я знаю, что TS и JS являются асинхронными, и эта проблема вызвана из-за этого, но я не смог найти правильный метод для решения моей проблемы. Любая помощь будет оценена.

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

У меня была эта общая проблема, когда я только начинал изучать Observables / Reactive программирования с помощью приложения Google Maps: D!

Вскоре вы поняли, что асинхронная функция еще не изменила логический флаг b, когда функция синхронно возвращает b (по умолчанию true);

Чтобы исправить это, может быть проще реструктурировать вашу функцию, чтобы она возвращала Observable вызывающей стороне.

и, возможно, посмотрите Observable цепочка или похожее понятие Promise цепочка.

Старый пример:

CheckRegUser(u: User): boolean {
    const b: boolean = true;
    const toSend = {
      email: u.email
    };

    const httpPost: Observable<aJsonObject> = this.http.post("http://localhost:8080/", toSend)
    const httpPostSubscription: Subscription = httpPost
      .subscribe((data: Valid) => { // This is asynchronous
        if (!data.validity) {
          b = false;
        }
      });
    console.log(b);

    return b; // This is effectively sync returning your default value `b = true`;
  }

Было бы лучше, если бы вы могли переименовать свои переменные, чтобы они были понятнее. b или isDataValid. Рекомендуется также начинать функциональный стиль с const переменных, чтобы избежать проблем с изменчивостью.

Если вы более знакомы с Promises, вы также можете попробовать promisify httpClient.post Observable.

Суть в том, чтобы передать Observable обратно вызывающей стороне и .subscribe там. Когда что-то возвращается асинхронно, вы должны вернуть асинхронность обратно наверх.

Код рефакторинга для отражения этих практик

  CheckRegUser(user: User, httpClient: HttpClient): Observable<Valid> {
    // 1. Data to send
    type  EmailPost                  = { email: string }
    const emailJsonToSend: EmailPost = { // I prefer explicit typing wherever possible :tada: :D
      email: user.email
    };

    // 2. POST the data to the web server
    const emailHttpPostObs: Observable<Valid> = httpClient.post("http://localhost:8080/", emailJsonToSend);

    return emailHttpPostObs;
  }

  CallerSubmitUserFunction(user: User, httpClient: HttpClient) {
    // Made some assumptions, please comment and we can work out a better solution
    // Explicitly typed things as an example.

    // 1. You have a user e.g. new User(name:'myUser', email: 'myEmailAddressOrEmailContent@email.com');
    const userToSend: User = user;
    // 2. You POST the user.email and get response.
    const validatedUserDataObs: Observable<Valid> = CheckRegUser(userToSend, httpClient);

    // 3. You check whether the server accepted the data and whether it was valid.
    const validatedUserDataObs: Subscription = validatedUserDataObs
      .subscribe((data: Valid) => {
        // Perform data validation or Error checking here.

        // If data is valid, 
        if (dataValidationFunction()) {
          // Do something here
          // Instead of trying to return the boolean in the asynchronouse function.
          // Directly do something after the server responds (whenever it happens).
        }
      }) // catch Error


    // It would also be better if you could rename your variables to be more self-indicative
    // var dataIsValid

  }
0 голосов
/ 04 июля 2018

Вы можете попробовать с async await

  async CheckRegUser(u: User): Promise<boolean> {

    let toSend = {
      email: u.email
    };
    let k = await this.http.post("http://localhost:8080/", toSend).subscribe((data: Valid){
      let b: boolean = true;
      if(!data.validity){
        b = false;
      }
      return b
    });
    console.log(k);
    return k;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...