JS 使用 ReadableStream 实现响应下载进度

58 min read

您可以使用 JavaScript 的 ReadableStream 来实现带有下载进度的响应。下面是一个示例代码,演示了如何使用 fetch 函数和 ReadableStream 来获取文件并显示下载进度:

// 获取文件的下载进度
function getDownloadProgress(response, onProgress) {
  const contentLength = response.headers.get('content-length');
  let receivedBytes = 0;

  return new Response(
    new ReadableStream({
      start(controller) {
        const reader = response.body.getReader();

        function read() {
          reader.read().then(({ done, value }) => {
            if (done) {
              controller.close();
              return;
            }

            receivedBytes += value.byteLength;
            onProgress(receivedBytes, contentLength);

            controller.enqueue(value);
            read();
          });
        }

        read();
      }
    })
  );
}

// 下载文件
function downloadFile(url, onProgress) {
  fetch(url).then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    return getDownloadProgress(response, onProgress);
  }).then(downloadResponse => {
    const disposition = response.headers.get('content-disposition');
    const filenameMatch = disposition.match(/filename="([^"]+)"/);
    
    const filename = filenameMatch && filenameMatch[1] ? filenameMatch[1] : 'download.file';
    const blob = downloadResponse.blob();
    
    // 将文件下载到本地
    const link = document.createElement('a');
    link.href = URL.createObjectURL(blob);
    link.download = filename;
    link.click();

    URL.revokeObjectURL(link.href);
  }).catch(error => {
    console.error(error);
  });
}

// 在页面上显示下载进度
function updateProgress(receivedBytes, contentLength) {
  const progressPercent = (receivedBytes / contentLength * 100).toFixed(2);
  console.log(`Downloaded ${progressPercent}%`);
}

// 开始下载文件
downloadFile('https://example.com/somefile.pdf', updateProgress);

在上面的代码中,getDownloadProgress 函数使用 ResponseReadableStream 来创建一个新的响应对象,该对象在每次读取文件内容时更新下载进度。在 downloadFile 函数中,获取文件的响应会被传递给 getDownloadProgress,并开始读取内容。然后,将包含文件内容的响应保存为 blob,并使用 a 标签的 download 属性下载文件到本地。

updateProgress 函数用于在页面上显示下载的进度,可以根据自己的需要进行修改。

请注意,ReadableStream 是一项实验性功能,在某些浏览器中可能不受支持。如果需要兼容性,请考虑使用其他方法来实现下载进度的功能。