异步/等待阻止执行第二个承诺

时间:2018-09-13 00:03:43

标签: reactjs promise async-await try-catch

让我说我有登录功能

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,无论this.login();的承诺返回结果还是错误,函数都会运行,无论发生什么情况。

3 个答案:

答案 0 :(得分:2)

这是the answer to the previous question中提到的问题,

  

登录的问题是其控制流程有缺陷。它无法抑制错误,因此无法有效捕获错误。

.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中重新引发的错误将传播到错误边界组件,否则将导致demo异常。

可能会向DRY try {...} catch (err) { this.setState({ error: err }) }样板引入一些额外的帮助。

答案 1 :(得分:1)

为什么不将api.login()放在第一个登录承诺then回调中?

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});
    api.login() // <----- if you want to check result just wrap it in an if statement if (result) api.login()
    return result;
  })
  .catch(error => console.log('error:', error));

};

否则,您可以使login()返回一个布尔值或真实/虚假值,然后执行以下操作(未经测试的代码):

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

答案 2 :(得分:1)

我认为这可能是因为您只是在catch方法中运行console.log而不是抛出错误或拒绝Promise。因此,您等待的try / catch块将继续运行,好像一切正​​常。尝试使用Promise.reject或新的Error()引发错误。

var catchWithoutRejection = async () => {
  await console.log('hello')
  console.log('running')
}

catchWithoutRejection();

// hello
// running
// Promise {<resolved>: undefined}

var catchWithRejection = async () => {
  await Promise.reject("hello")
  console.log('not running')
}

catchWithRejection();
// Promise {<rejected>: "hello"}