【问题标题】:Return value with asynchronous functions in Typescript在 Typescript 中使用异步函数返回值
【发布时间】:2018-12-12 11:12:45
【问题描述】:

我有以下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 是异步的,因此导致了这个问题,但是我找不到解决问题的正确方法。任何帮助,将不胜感激。

【问题讨论】:

标签: javascript typescript asynchronous


【解决方案1】:

你可以试试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;
}

【讨论】:

  • 请注意,这意味着CheckRegUser将返回的不是boolean,而是Promise&lt;boolean&gt;,并且应该在调用代码中进行相应的处理(通过then,也可以通过@987654327 @)。
  • @Cerberus 我同意你的观点,async/await 的回归是一个承诺
  • 感谢您的回复,解决了我的问题!!并感谢@Cerberus 指出异步返回了一个承诺。
  • 承诺不是价值!为什么这是公认的答案?
  • @iGanja 因为async 函数返回承诺?
【解决方案2】:

当我刚开始使用 Google 地图应用学习 Observables/Reactive 编程时,我遇到了这个常见问题:D!

当你发现异步函数同步返回b(默认为true)时,你意识到异步函数还没有改变b布尔标志;

要解决此问题,重组函数以将 Observable 返回给调用者可能会更容易。

也许可以查找Observablechaining 或类似概念Promisechaining。

老例子:

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

  }

【讨论】:

  • 感谢您非常详细的回答,它确实解释得很好,但我更愿意为我的问题提供一个简单明了的解决方案。但是,再次感谢您为编写此答案所付出的努力!
猜你喜欢
  • 2018-04-08
  • 2019-02-27
  • 1970-01-01
  • 2016-06-22
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
相关资源
最近更新 更多