Async / Await предотвращает выполнение второго обещания - PullRequest
0 голосов
/ 13 сентября 2018

Допустим, у меня есть функция входа в систему

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));
  }; 

Затем я хочу вызвать функцию onSubmit в React следующим образом. Если функция возвращает ошибку по какой-либо причине. Как предотвратить запуск следующей функции в этом случае api.login()?

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

Имеет ли смысл попытка / отлов в этом случае? Я пробовал несколько вариантов, включая встроенный метод catch catch, и функция запускается независимо от того, что произойдет, как только обещание из this.login(); вернет либо результат, либо ошибку.

Ответы [ 3 ]

0 голосов
/ 13 сентября 2018

Я думаю, это может произойти, потому что вы просто запускаете console.log в своем методе catch, вместо того, чтобы выдавать ошибку или отклонять Promise.Таким образом, блок try / catch для вашего await продолжает работать, как будто все в порядке.Попробуйте сгенерировать ошибку с Promise.reject или new 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"}
0 голосов
/ 13 сентября 2018

Эта проблема упоминается в ответе на предыдущий вопрос ,

Проблема с входом в систему состоит в том, что его поток управления имеет недостатки.Он не может эффективно отлавливать ошибки, потому что он их подавляет.

.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, будет распространяться до компонента границы ошибки или приведет к исключению,a demo .

Некоторые дополнительные помощники могут быть добавлены к шаблону DRY try {...} catch (err) { this.setState({ error: err }) } up.

0 голосов
/ 13 сентября 2018

Почему бы не поместить 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>
...