Проблема с обещаниями и асинхронными операциями - PullRequest
1 голос
/ 19 июня 2019

Я должен сделать HTTP-запрос POST к серверу, дождаться ответа сервера и затем сделать другой запрос (который отправит некоторые данные ответа сервера обратно на сервер).Я думал, что это простая задача, и я сделал что-то вроде этого:

 const promise = new Promise((resolve, reject) => {
        resolve(this.updatePU(name, 'text', selectedOption.code));
      })
      promise.then(() => {
        console.log('Calling checkExpress function');
        let express = '';
        const puOrderNo = this.props.puOrderNo;
        fetch('/CheckExpress', {
          crossDomain: true,
          method: 'POST',
          headers: {
            'Accept': 'text/xml',
            'Content-Type': 'application/json',
          },
            body: JSON.stringify({"puOrderNo": puOrderNo })
        })
        .then(response => response.text())
        .then(str => {  
            express = convert.xml2json(str);
        }).then(() => {
            const data = JSON.parse(express);
            const checkExpress = data['elements'][0].elements[0].elements[0].elements[0].elements[0].text;
            console.log('checkExpress:', checkExpress);
            if(checkExpress === 'true'){
              this.props.updatePackageTypeField(true)
            } else {
              this.props.updatePackageTypeField(false);
            }
        })
        .catch(err => console.log(err));
      })

Функция updatePU также является асинхронной функцией:

 updatePU = (name, type, value) => {
    const PUOrderNo = this.props.puOrderNo;
    const updatedValue = type === 'text' ? (`'${name}': '${value}'`) : (`'${name}': ${value}`);

    fetch('/ModifyPUOrder', {
      crossDomain: true,
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
        body: JSON.stringify({
          updatedValue: updatedValue,
          puOrderNo: PUOrderNo
        }),
    })
    .then(response => {
      if(response.ok){
        return response.json();
      } else {console.log(response)}
      throw new Error('Request failed!');
    }, networkError => {
      console.log(networkError.message);
    })
    .then(data => {
      if ("error" in data) {
        alert(data.error.message);
        this.refresh();
      }
      this.props.updatePUOrderForm(data);
    });
   }

В результате обещание игнорируется (Iдумаю) и второй запрос сделан раньше первого!Я понимаю, что проблема в том, что функция, которая разрешается в обещании, также является асинхронной, но я не уверен, что делать.

Любая помощь будет принята с благодарностью!

1 Ответ

1 голос
/ 19 июня 2019

Основная проблема в том, что updatePU не возвращает обещание. Вы должны вернуть результат цепочки обещаний, добавив return перед fetch:

return fetch('/ModifyPUOrder', {

Тогда в вашем коде вверху не создавайте новое обещание, используйте одно из updatePU:

this.updatePU(name, 'text', selectedOption.code)
.then(() => {
    console.log('Calling checkExpress function');
    // ...

Есть вторая (в основном не связанная) проблема: вы преобразуете сетевую ошибку (отклонение) в выполнение:

.then(response => {
  if(response.ok){
    return response.json();
  } else {console.log(response)}
  throw new Error('Request failed!');
}, networkError => {                 // ***
  console.log(networkError.message); // *** Converts rejection to fulfillment with `undefined`
})                                   // ***

Помните, что каждый обработчик в цепочке преобразует то, что проходит через него. Обработчик отклонения, который не выдает или не возвращает обещание, которое отклоняет, преобразует отклонение в исполнение.

Вместо того, чтобы добавлять console.log для повсеместного сброса ошибок, просто распространяйте цепочку, а на верхнем уровне, где вы не можете распространять цепочку дальше, просто добавьте окончательный .catch, который сообщает / обрабатывает ошибку (что у вас есть в вашем первом блоке кода).

См. *** комментарии для заметок об этом и нескольких других вещах:

updatePU = (name, type, value) => {
    const PUOrderNo = this.props.puOrderNo;
    const updatedValue = type === 'text' ? (`'${name}': '${value}'`) : (`'${name}': ${value}`);

    return fetch('/ModifyPUOrder', {
      crossDomain: true,
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
        body: JSON.stringify({
          updatedValue: updatedValue,
          puOrderNo: PUOrderNo
        }),
    })
    .then(response => {
      if(response.ok){
        return response.json();
      } // *** No console.log here
      throw new Error('Request failed!'); // *** I wouldn't hide what happened, perhaps: `throw new Error("HTTP error " + response.status);`
    }/* ***No rejection handler here */)
    .then(data => {
      if ("error" in data) {
        alert(data.error.message);
        this.refresh();
        // *** You presumably want to return here or use `else` so you don't update the form below...?
      }
      this.props.updatePUOrderForm(data);
    });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...