【问题标题】:javascript/react - async/await with for loop POST requestsjavascript/react - 带有 for 循环 POST 请求的异步/等待
【发布时间】:2018-11-20 02:04:42
【问题描述】:

我正在创建一个图片转换器,其中我的 JS 代码从用户那里获取文件输入,将其发送到我的 python 后端,在那里它们被转换并保存到一个文件夹中。然后 Python 将响应发送回 JS (react),JS 将每个文件的状态单独更新为“已转换”并重新渲染必要的组件。

我有一个为每个文件发送单独的 POST 请求的 for 循环。这很好,直到我想在转换所有文件后为整个目录创建一个 .zip。我的问题就在那里。我的 zip 总是返回空的或包含不完整的文件。

// function which takes the file inputs from user
uploadBatch = async () => {
  const files = this.getFilesFromInput();
  const batch = Math.floor(Math.random() * 999999 + 100000);
  for (let i = 0; i < files.length; i++) {
    // sets the state which will then be updated
    await this.setState(
      {
        files: [
          ...this.state.files,
          {
            // file state values
          }
        ]
      },
      () => {
        const formData = new FormData();
        // appends stuff to form data to send to python
        axios
          .post('/api/upload', formData, {
            headers: {
              'Content-Type': 'multipart/form-data'
            },
            responsetype: 'json'
          })
          .then(response => {
            // update the state for this particular file
          });
      }
    );
  }
  return batch;
};

// function which zips the folder after files are converted
handleUpload = async e => {
  e.preventDefault();
  // shouldn't this next line wait for uploadBatch() to finish before 
  // proceeding?
  const batch = await this.uploadBatch();
  // this successfully zips my files, but it seems to run too soon
  axios.post('/api/zip', { batch: batch }).then(response => {
    console.log(response.data);
  });
};

我使用过 async/await,但我认为我没有很好地使用它们。我不太了解这个概念,因此非常感谢您的解释。

【问题讨论】:

标签: javascript reactjs asynchronous


【解决方案1】:

无论何时调用setState(),组件都会重新渲染。理想情况下,您应该完成所有操作并在最后致电setState()。

这样的事情应该会为你工作

// function which takes the file inputs from user
uploadBatch = async () => {
  const files = this.getFilesFromInput();
  const batch = Math.floor(Math.random() * 999999 + 100000);
  const files = [];
  for (let i = 0; i < files.length; i++) {
    const formData = new FormData();
    // appends stuff to form data to send to python
    const res = 
      await axios
        .post('/api/upload', formData, {
          headers: {
            'Content-Type': 'multipart/form-data'
          },
          responsetype: 'json'
        });

    files.push('push data into files arr');
  }

  return { files, batch };
};

// function which zips the folder after files are converted
handleUpload = async e => {
  e.preventDefault();
  // get batch and files to be uploaded and updated
  const { files, batch } = await this.uploadBatch();
  // this successfully zips my files, but it seems to run too soon
  await axios.post('/api/zip', { batch: batch }).then(response => {
    console.log(response.data);
  });

  // set the state after all actions are done
  this.setState( { files: files });
};

【讨论】:

  • 我实际上想每次都重新渲染,因为我想显示每个正在上传的文件的文件状态(正在转换... -> 已转换)。一旦每个文件被转换,Python 就会发送一个响应,然后响应更新状态。问题是我需要handleUpload 等待所有状态都被转换,然后再发送压缩请求。
  • 然后您需要将所有内容存储在状态中,例如batch、allFilesUploaded,并在上传后更新每个文件的状态。您将需要使用allFilesUploaded 状态值来触发/api/zip POST 调用。
  • 我考虑过,这肯定会奏效。但是使用 async/await 不是更好的方法吗?
  • setState() 将在每次执行时触发重新渲染,即使您使用async-await,您也永远不会到达该方法的结尾。通过推迟渲染更新状态后,您无法继续执行逻辑。
  • 我没有推迟任何渲染!我只是想在运行另一个发布请求之前等待 for 循环完成。无论如何,我用async-await 修复了它,因为我怀疑它会起作用。我只需要包含promises 并告诉我的代码等待这些。明天我将为可能遇到此问题的其他人回答我自己的问题!感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2021-12-24
  • 1970-01-01
  • 2019-03-14
  • 1970-01-01
  • 1970-01-01
  • 2020-04-20
  • 2018-11-11
  • 2021-10-18
相关资源
最近更新 更多