javascript обработка обещаний, ошибка обработки - PullRequest
2 голосов
/ 20 марта 2020

Мне трудно понять, что я делаю неправильно. У меня есть функция, которая получает URL-адрес, по которому следует сделать запрос GET, в случае успеха должен заполнить комбо полученными данными (это зависит от того, какая функция вызывает их), в случае сбоя он должен выполнить какой-то общий код.

    getFirstCombo = () => {
        this.getFromApi('/First/GetAll')
            .then(data => this.setState({firstComboOptions: this.parseCombo(data)}))
            .catch(error => console.log('ERROR2: ', error));
    }

    getSecondCombo = () => {
        this.getFromApi('/Second/GetAll')
            .then(data => this.setState({secondComboOptions: this.parseCombo(data)}))
            .catch(error => console.log('ERROR2: ', error));
    }

    parseCombo = (data: any) => {
        const combo = data.map(item => (
            { label: item.description, value: item.id }
        ));
        return combo;
    }

    getFromApi = (url: string) : Promise<any> => {
        return restApiAxios.get(url)
        .then(response => {
            return response.data;
        })
        .catch(error => {
            console.log('ERROR: ', error);
        });
    }

этот код выполняется на componentDidMount реактивного компонента, но при сбое он сначала печатает:

ERROR:  Error: Network Error
    at createError (createError.js:16)
    at XMLHttpRequest.handleError (xhr.js:83)

и сразу после:

PanelDatos.tsx:50 ERROR2:  TypeError: Cannot read property 'map' of undefined
    at PanelDatos.parseCombo (PanelDatos.tsx:55)
    at PanelDatos.tsx:50

таким образом, при ошибке выполняется блок catch из getFromApi , а затем он пытается выполнить блок затем в getFirstCombo , что вызывает catch блок из той же функции, потому что данные не существуют, почему это так? Разве он не должен просто выполнить первый catch ? заранее спасибо

Ответы [ 2 ]

2 голосов
/ 20 марта 2020

.catch возвращает обещание, очень похожее на .then, что позволяет вам возвращать пользовательское значение и обрабатывать его таким образом.

Попробуйте выполнить следующее, чтобы наблюдать эффект:

Promise
  .reject(1)
  .catch(e => e) // Catch the error and return it
  .then(console.log) // will log 1 to the console

Это означает, что вам нужно будет добавить некоторые проверки, если вы хотите продолжать использовать обещания, подобные этому:

Promise
  .reject(new Error('haha'))
  .catch(err => ({err}))
  .then(({err, data}) => {
    if(err) return // Do nothing
    // enter code here
  })

Однако использование async / await улучшит читабельность еще больше:

getFirstCombo = async () => {
  let response
  try {
    response = await this.getFromApi('/First/GetAll')
  } catch (e) {
    return // Exit early
  }
  let parsed
  try {
    parsed = this.parseCombo(data)
  } catch (e) {
    console.log(e)
    return // Exit early
  }
  return this.setState({firstComboOptions: parsed})
}

И, конечно, добавьте ошибку снова в ваш блок catch в вашем API, чтобы он мог обрабатывать вызовы API.

1 голос
/ 20 марта 2020

Это происходит потому, что внутри getFromApi метода catch для ошибки вы ничего не возвращаете, поэтому по умолчанию он возвращает разрешенное обещание с ответом null, и выполнение идет внутри getFirstCombo метода затем, вызывая другой ошибка. Вы можете обновить свой код, чтобы решить эту проблему следующим образом:

getFromApi = (url: string): Promise<any> => {
   return restApiAxios.get(url)
      .then(response => response.data)
      .catch(error => Promise.reject(error));
}

Функция stati c Promise.reject возвращает Promise, которое отклонено. Таким образом, он будет go непосредственно в catch везде, где вызывается getFromApi.

DEMO:

async function getFromApi(url) {
   return fetch(url) // rejects
      .then(response => response.json())
      .catch(err => Promise.reject(err))
}
async function getFirstCombo() {
   getFromApi('https://no-such-server.abcd')
      .then(data => console.log('data: ', data))
      .catch(error => console.log('ERROR2: ', error));
}
getFirstCombo()

DEMO # 2 (с функцией getFirstCombo без блока захвата) :

async function getFromApi(url) {
  return fetch(url) // rejects
    .then(response => response.json())
    .catch(err => {
      console.log('ERROR in getFromApi(): ', err);
      return null;  // return null, empty array, 0 or false... as per your requirement
    })
}
async function getFirstCombo() {
  getFromApi('https://no-such-server.abcd')
    .then(data => console.log('data: ', data))
    // Same value set in catch block of getFromApi will return in this then() block
    // Validate this `data` variable before processing it further like:
    // if(data === null) this means an error had occurred
    // else continue with your logic
}
getFirstCombo()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...