Два циклических асинхронных вызова, за которыми следует вызов синхронизации

#javascript #reactjs #loops #promise #fetch

#javascript #reactjs #циклы #обещание #выборка

Вопрос:

Мне нужно отредактировать ранее сохраненные сообщения, содержащие вложения. В функции редактирования пользователь должен иметь возможность редактировать заголовок или текст сообщения, заменять существующие вложения или удалять вложения.

Сценарий: пользователь внес изменения в текст сообщения, заменил одно вложение и удалил 2 вложения и нажал Сохранить. При нажатии кнопки сохранения должны выполняться следующие действия

  1. Сначала заменяйте и удаляйте асинхронные вызовы API
  2. Если замена и удаление выполнены успешно, то вызов api для сохранения изменений в тексте

Вот где я нахожусь..

.then Promise.all in replace и delete выполняется до завершения обещания цикла, в результате чего внешнее обещание (in handleSave ) всегда получает разрешенное обещание.

deleteData и replaceData являются массивами, содержащими данные, подлежащие замене / удалению

 const delete = () => {
    if (deleteData.length > 0) {
      return Promise.all([
        deleteData.map(data => fetch(url)
          .then((response) => {
            if (!response.ok) {
              throw new Error('Delete Failed');
            }
          })
        ),
      ]).then(() => Promise.resolve('Deleted'));
    }
    return Promise.resolve('Nothing to delete');
  };

const replace = () => {
    if (replaceData.length > 0) {
      return Promise.all([
        replaceData.map(data => fetch(url)
          .then((response) => {
            if (response.status === 400) {
              response.text().then((error) => {
                const errorObject = JSON.parse(error);
                throw new Error(error);
              });
            } else if (!response.ok) {
              throw new Error('Update Failed');
            }
          })
        ),
      ]).then(() => Promise.resolve('Replaced'));
    }
    return Promise.resolve('Nothing to replace');
  };

const saveMessage = () => {
    fetch(saveUrl)
        .then((response) => {
            if (response.status === 400) {
              response.text().then((error) => {
                const errorObject = JSON.parse(error);
                throw new Error(error);
              });
            } else if (!response.ok) {
              throw new Error('Save Failed');
            }
        });
}

const handleSave = () => {
  Promise.all([replace, delete])
     .then(() => {
       saveMessage();
      }).catch((e) => {
        //Catch action
      })
  }
  

Комментарии:

1. Ваш save ничего не возвращает, вы, вероятно, хотите return выполнить вызов выборки, чтобы его можно было перехватить ниже в handleSave

Ответ №1:

В ваш Promise.all s вы в настоящее время передаете массив, содержащий один элемент, где этот элемент представляет собой массив обещаний. В результате Promise.all проблема немедленно устраняется.

Promise.all Вместо этого передайте массив обещаний, то есть просто .map нет [data.map(...)] . Изменить:

 return Promise.all([
  deleteData.map(data => fetch(url)
  

Для

 return Promise.all(
  deleteData.map(data => fetch(url)
  

и

 return Promise.all([
  replaceData.map(data => fetch(url)
  

Для

 return Promise.all(
  replaceData.map(data => fetch(url)
  

Кроме того, внутри replace он не возвращает внутреннее .text обещание при возникновении ошибки 400, поэтому его сопоставление Promise.all не будет отклоняться, когда вы этого захотите. Изменить:

 if (response.status === 400) {
  response.text().then((error) => {
    const errorObject = JSON.parse(error);
    throw new Error(error);
  });
  

Для

 if (response.status === 400) {
  return response.json().then((error) => {
    throw new Error(error);
  });
  

(обратите внимание, что вы можете использовать .json() вместо JSON.parse )

Кроме того, чтобы ваши saveMessage ошибки обрабатывались в catch , вы также должны возвращать каждое из его обещаний:

 const saveMessage = () => {
  return fetch(saveUrl)
    .then((response) => {
      if (response.status === 400) {
        return response.json().then((error) => {
          throw new Error(error);
        });
      } else if (!response.ok) {
        throw new Error('Save Failed');
      }
    });
};

  

Комментарии:

1. Спасибо, но проблема не в этом.. Проблема в том, что циклы в replace и delete работают не так, как ожидалось. Я предпочитаю сохранить .text(), потому что, если ответ пуст.json() завершается с ошибкой

2. Это определенно, по крайней мере, одна часть проблемы. Можете ли вы показать, где вы определяете deleteData , replaceData , replace , delete ?

3. deleteData и replaceData — это массивы, содержащие данные, подлежащие замене / удалению

4. Я вижу проблему, вы передаете массив массивов Promise.all вместо массива обещаний.

5. Вы уверены, что добавили return ? То есть return response.text() или .json() вместо просто response.text() или .json() ?