首页 > 解决方案 > 异步/等待防止第二个承诺执行

问题描述

假设我有一个登录功能

login = () => {
    let url = baseURL + '/user/login?_format=json';  

    let data = {
      "name": this.state.email,  
      "pass": this.state.password
    };


    return axios({
      url,
      method: "POST",
      headers: {
        'Accept':  'application/json',
        'Content-Type': 'application/json',
      },
      withCredentials: true,
      credentials: 'same-origin'
      })
      .then(function(result) {
        console.log('result:', result);
        this.setState({csrfToken: result.data.csrf_token}); 
        this.setState({logoutToken: result.data.logout_token});
        return result;
      })
      .catch(error => console.log('error:', error));
  }; 

然后我想在 React 中调用 onSubmit 函数,如下所示。如果函数因任何原因返回错误。在这种情况下,如何防止api.login()运行下一个函数?

{api => (
            <Form
                onSubmit={async e => {
                  e.preventDefault();
                  await this.login();
                  api.login()
                }}
              >
    <input/>
    </Form>

在这种情况下,try/catch 有意义吗?我已经尝试了几个选项,包括内联 try catch,只要 promise fromthis.login();返回结果或错误,无论发生什么,该函数都会运行。

标签: reactjspromiseasync-awaittry-catch

解决方案


这是上一个问题的答案中提到的问题,

登录的问题在于它的控制流程是有缺陷的。它不能有效地捕获错误,因为它会抑制它们。

.catch(error => console.log('error:', error))抑制错误,而它不应该用于正确的控制流。拒绝应该在使用承诺的顶层处理。即使需要处理错误catch(根本不需要console.log),也应该重新抛出它。

异步错误的一致处理是 React 中的一个单独关注点。需要在生命周期钩子中同步捕获和重新抛出异步错误(可能componentDidUpdate):

  componentDidUpdate() {
    if (this.state && this.state.error) {
      throw this.state.error;
    }
  }

  onSubmit = async e => {
    try {
      e.preventDefault();
      await this.login();
      api.login();
    } catch (err) {
      this.setState({ error: err });
    }
  }

  render() {
    ...
    <Form onSubmit={this.onSubmit}>
      <input/>
    </Form>
    ...
  }

重新抛出的错误componentDidUpdate将传播到错误边界组件或将导致异常,演示

一些额外的助手可能会被引入 DRYtry {...} catch (err) { this.setState({ error: err }) }样板。


推荐阅读