关键词

JS实现可恢复的文件上传示例详解

下面是关于JS实现可恢复文件上传的详细攻略。

标题

什么是可恢复文件上传?

可恢复文件上传是指,当文件上传被中断或者失败时,重新连接服务器上传时,上传的过程能够从之前的进度恢复,并继续上传。这样可以节省时间和流量,提高用户体验。

如何实现可恢复文件上传

可恢复文件上传的实现需要前后端的配合,下面我会先讲述前端的实现方式。

文件分片及上传控制

将要上传的文件分片,并记录每一个分片的编号以及上传状态。上传的时候,控制分片的上传顺序,确保分片有序上传。

控制并发上传的分片数量

可恢复文件上传的上传过程通常会通过多个分片同时上传的方式实现,我们需要控制同时上传的分片数量,防止过多的并发请求对服务器造成负担。

上传失败恢复

文件上传过程可能会因为各种原因发生失败,我们需要在上传过程中记录每一个上传成功的分片,当上传失败时,能够根据记录重新上传上传失败的部分。

上传进度显示

用户需要及时的掌握上传进度,需要实时显示上传进度,包括上传进度百分比、已上传的文件大小和总文件大小等。

示例说明

示例一
// 实现分片上传的方法,将文件分为多个小文件进行上传
function chunkUpload(url, file) {
  const chunkSize = 1 * 1024 * 1024; // 每个分片的大小
  const totalSize = file.size; // 文件总大小
  let start = 0; // 上传起始位置
  let end = chunkSize; // 上传结束位置
  let index = 0; // 上传分片编号
  const chunks = Math.ceil(totalSize / chunkSize); // 文件分片总数
  const xhr = new XMLHttpRequest();
  xhr.open('POST', url, true);
  xhr.setRequestHeader('Content-Type', 'application/octet-stream');

  // 上传前检查,若上一次该分片上传了,则跳过该分片
  if (localStorage.getItem(file.size.toString())) {
    const uploadedChunks = JSON.parse(localStorage.getItem(file.size.toString()));
    start = uploadedChunks[0];
    index = uploadedChunks[1];
    end = start + chunkSize;
  }

  xhr.onload = function() {
    if (xhr.status === 200 || xhr.status === 201) {
      const uploadedChunks = JSON.parse(localStorage.getItem(file.size.toString())) || [];
      uploadedChunks.push([start, index]);
      localStorage.setItem(file.size.toString(), JSON.stringify(uploadedChunks));
      start = end;
      if (start < totalSize) {
        end = start + chunkSize;
        index++;
        chunkUpload(url, file, start, end, index, chunks);
      } else {
        console.log('文件上传完成');
      }
    } else {
      // 上传失败后的处理
    }
  };

  xhr.send(file.slice(start, end));
}

上述代码是一个简单的文件分片上传的实现,用于后面的上传控制以及失败恢复的示例代码。

示例二
// 实现并发上传控制的方法,例如并发上传5个文件分片
function concurrentUpload(url, file) {
  const concurrent = 5; // 并发上传分片数量
  const promises = [];
  const chunkSize = 1 * 1024 * 1024; // 每个分片的大小
  const totalSize = file.size; // 文件总大小
  const chunks = Math.ceil(totalSize / chunkSize); // 文件分片总数
  for (let i = 0; i < chunks; i += concurrent) {
    const chunkPromises = [];
    for (let j = i; j < i + concurrent; j++) {
      if (j < chunks) {
        chunkPromises.push(
          new Promise((resolve, reject) => {
            const start = j * chunkSize;
            const end = Math.min(start + chunkSize, totalSize);
            const chunk = file.slice(start, end);
            const xhr = new XMLHttpRequest();
            if (localStorage.getItem(file.size.toString())) {
              const uploadedChunks = JSON.parse(localStorage.getItem(file.size.toString()));
              if (uploadedChunks.includes(j)) {
                resolve();
              }
            }
            xhr.open('POST', url, true);
            xhr.setRequestHeader('Content-Type', 'application/octet-stream');
            xhr.onload = function() {
              if (xhr.status === 200 || xhr.status === 201) {
                const uploadedChunks = JSON.parse(localStorage.getItem(file.size.toString())) || [];
                uploadedChunks.push(j);
                localStorage.setItem(file.size.toString(), JSON.stringify(uploadedChunks));
                console.log(`第${j+1}个分片上传成功`);
                resolve();
              } else {
                // 上传失败后的处理
              }
            };
            xhr.send(chunk);
          })
        );
      } else {
        break;
      }
    }
    promises.push(chunkPromises);
  }

  // Promise.all将并发请求进行包装
  const wrappedPromises = promises.map(chunkPromises => {
    return new Promise((resolve, reject) => {
      Promise.all(chunkPromises).then(() => {
        console.log('一组并发请求完成,继续下一组');
        resolve();
      });
    });
  });

  Promise.all(wrappedPromises).then(() => {
    console.log('分片上传完成');
  });
}

上述代码中,我们实现了并发上传控制的逻辑,通过分组的方式,分别上传每一组分片,并且同一组中并发请求的数量控制在5以内,实现了对服务器的较小压力。

结论

通过上述实现,就可以很好的实现可恢复文件上传,使得文件上传不再因为各种原因而失败,同时也能够大幅提升文件上传的效率和体验。

本文链接:http://task.lmcjl.com/news/8980.html

展开阅读全文