在Typescript中使用异步函数返回值

时间:2018-07-04 05:37:03

标签: javascript typescript asynchronous

我具有以下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后端,并且返回了布尔结果。这部分工作正常,但问题是在“ this.http”中更改b的值之前执行了“ return b”语句,因此无论Express的响应如何,b始终为真。 >

我知道TS和JS是异步的,因此引起此问题,但是我找不到解决我问题的正确方法。任何帮助,将不胜感激。

2 个答案:

答案 0 :(得分:3)

您可以尝试使用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;
}

答案 1 :(得分:2)

当我刚开始使用Google Maps应用程序学习Observables / Reactive编程时,我也遇到了这个常见问题: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`;
  }

最好重命名变量以使其更清晰。 bisDataValid。 最好以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

  }