首页 > 解决方案 > 异步循环似乎部分并行

问题描述

我正在尝试实现一个函数,它将文件切成块,然后将它们一个接一个地发送到我的后端。

该函数必须在开始上传之前对每个文件进行哈希处理并验证哈希是否已知。以下代码是代码部分,其中调用了我的有问题的函数。

        process: async (
          fieldName,
          file,
          metadata,
          load,
          error,
          progress,
          abort,
          transfer,
          options,
        ) => {
          // fieldName is the name of the input field - No direct relevance for us
          // logger.log(`fieldName: ${fieldName}`);

          // Usually Empty - Can be added with Metadata-Plugin
          // logger.log(metadata);

          const source = this.$axios.CancelToken.source();

          const abortProcess = () => {
            // This function is entered if the user has tapped the cancel button
            source.cancel('Operation cancelled by user');

            // Let FilePond know the request has been cancelled
            abort();
          };

          let chunks = [];

          const {
            chunkForce,
            chunkRetryDelays,
            chunkServer,
            chunkSize,
            chunkTransferId,
            chunkUploads,
          } = options;

          // Needed Parameters of file
          const { name, size } = file;

          if (chunkTransferId) {
            /** Here we handle what happens, when Retry-Button is pressed */
            logger.log(`Already defined: ${chunkTransferId}`);
            return { abortProcess };
          }

          this.hashFile(file)
            .then((hash) => {
              logger.log(`File Hashed: ${hash}`);
              if (hash.length === 0) {
                error('Hash not computable');
              }
              return hash;
            })
            .then((hash) => {
              logger.log(`Hash passed through: ${hash}`);
              return this.requestTransferId(file, hash, source.token)
                .then((transferId) => {
                  logger.log(`T-ID receieved: ${transferId}`);
                  return transferId;
                })
                .catch((err) => {
                  error(err);
                });
            })
            .then((transferId) => {
              transfer(transferId);
              logger.log(`T-ID passed through: ${transferId}`);

              // Split File into Chunks to prepare Upload
              chunks = this.splitIntoChunks(file, chunkSize);

              // Filter Chunks - Remove all those which have already been uploaded with success
              const filteredChunks = chunks.filter(
                (chunk) => chunk.status !== ChunkStatus.COMPLETE,
              );

              logger.log(filteredChunks);

              return this.uploadChunks(
                filteredChunks,
                { name, size, transferId },
                progress,
                error,
                source.token,
              ).then(() => transferId);
            })
            .then((transferId) => {
              // Now Everything should be uploaded -> Set Progress to 100% and make item appear finished
              progress(true, size, size);
              load(transferId);
              logger.log(transferId);
            })
            .catch((err) => error(err));

          return { abortProcess };
        },

uploadChunks是问题开始的地方。

    async uploadChunks(chunks, options, progress, error, cancelToken) {
      const { name, size, transferId } = options;
      for (let index = 0; index < chunks.length; index += 1) {
        let offset = 0;
        const chunk = chunks[index];
        chunk.status = ChunkStatus.PROCESSING;
        // eslint-disable-next-line no-await-in-loop
        await this.uploadChunk(chunk.chunk, options, offset)
          .then(() => {
            chunk.status = ChunkStatus.COMPLETE;
            offset += chunk.chunk.size;
            progress(true, offset, size);
            logger.log(offset); // This is always chunk.chunk.size, instead of getting bigger
          })
          .catch((err) => {
            chunk.status = ChunkStatus.ERROR;
            error(err);
          });
      }
    },
    uploadChunk(fileChunk, options, offset) {
      const { name, size, transferId } = options;
      const apiURL = `${this.$config.api_url}/filepond/patch?id=${transferId}`;
      return this.$axios.$patch(apiURL, fileChunk, {
        headers: {
          'content-type': 'application/offset+octet-stream',
          'upload-name': name,
          'upload-length': size,
          'upload-offset': offset,
        },
      });
    },

如您所见uploadChunks,需要一组块、一些选项、两个函数(进度和错误)和一个 cancelToken(我目前不使用,因为我仍然遇到这个问题)

数组中的每个块具有以下形式:

{
  status: 0, // Some Status indicating, if it's completed or not
  chunk: // binary data
}

该函数uploadChunks迭代块数组,理论上应该一个接一个地上传一个块,并且offset每次上传后总是递增,然后调用progress. 在此之后,它应该开始循环的下一次迭代,其中offset将比之前的调用更大。

调用本身一个接一个地执行,但每个调用都相同offsetprogress不会被重复调用。相反100%,由于load最后第一个函数中的 -call,我的进度条会锁定,直到所有内容都上传并且它们跳转到 。

因此,上传本身以正确的顺序正常工作,但是await this.uploadChunk...在每个块之后都不会调用所有代码并以某种方式阻塞。

标签: javascriptasynchronousasync-awaitaxios

解决方案


offset在循环内设置为 0 。所以偏移量总是0。你应该移动这条线:

let offset = 0;

for声明之前。


推荐阅读