纯前端 JS 实践批量打包并下载大文件

上网导航 2023-09-27 284 0条评论
摘要: 甲方客户甩来一个需求,需要把用户上传的视频、图片打包成zip并下载下来,并且要遵循一定的目录结构。原本需求定为后端实现,但经过后端同学调研了一波,发现会严重消耗后端的性能、带宽...

甲方客户甩来一个需求,需要把用户上传的视频、图片打包成zip并下载下来,并且要遵循一定的目录结构。原本需求定为后端实现,但经过后端同学调研了一波,发现会严重消耗后端的性能、带宽,遂卑微(niubi)前端上岗上线解决问题。

在谷歌、必应、百度...上调研了一波前端技术实现,大致找到两种解决方案,一是jszip + file-saver,二是streamSaver,下面介绍下这两种技术的使用。

jszip + file-saver

下载插件,随便附上github地址

jszip:github.com/Stuk/jszip

file-saver:github.com/eligrey/Fil…

npm install jszip file-saver

jszip + file-saver 使用方式比较简单,如下即可实现资源打包下载:

import JSZip from 'jszip';
import { saveAs } from 'file-saver';
(async() => {
  // 初始化一个zip打包对象
  const zip = new JSZip();
  // 创建一个名为images的新的文件目录
  const folder = zip.folder('images');
  // 请求远程资源的blob,其他文件,比如视频、表格等也是一样的
  const blob = await fetch('https://abc.com/test.png').then(response => response.blob())
  // 文件夹添加资源,图片也支持base64类型 {base64: true}
  folder.file('test.png', blob, { Blob: true });
  // 把打包内容异步转成blob二进制格式
  zip.generateAsync({type:"blob"}).then((content) => {
    // 下载压缩包
    saveAs(content, 'example.zip');
  });
})()

不过该方式有比较明显的缺陷,主要在兼容性及资源的体积上,在谷歌浏览器上能达到 2GB,但在其他浏览器上一般只支持到几百 MB,可参考下面的file-saver浏览器支持介绍:

所以,为了兼顾非谷歌浏览器的用户,还需要进一步地探索新的技术解决方案,也可以结合本公司对前端兼容性的要求来权衡。

streamSaver

streamSaver 的使用会稍微麻烦一点,不过按照官方的使用示例,也比较容易跑起来。

下载插件

npm install streamsaver

此外,还需要从github上下载几个文件到项目目录,分别是:

mitm.html:github.com/jimmywartin…

sw.js:github.com/jimmywartin…

zip-stream.js:github.com/jimmywartin…

streamSaver 的使用方式如下:

import streamSaver from 'streamsaver';
// gihub上下载的zip-stream.js
import '@/libs/streamsaver/zip-stream';
// mitm.html的存放目录,sw.js同级存放,都需要跟随项目部署到服务器
streamSaver.mitm = `${location.origin}/libs/streamsaver/mitm.html`;
// 初始化打包对象
const readableZipStream = new window.ZIP({
    async pull(ctrl) {
        // 请求资源 & 设置目录
        const res = await fetch('https://abc.com/test.png');
        const stream = () => res.body;
        const name = '/images/test.png';
        // 添加到处理队列,可遍历添加
        ctrl.enqueue({ name, stream });
        ctrl.close();
    },
});
// 资源命名
const fileStream = streamSaver.createWriteStream('example.zip');
// more optimized
if (window.WritableStream && readableZipStream.pipeTo) {
  return readableZipStream
    .pipeTo(fileStream)
    .then(() => {
      console.log('下载成功')
    })
    .catch((error) => {
      console.error('下载失败', error);
    })
}
// less optimized
const writer = fileStream.getWriter();
const reader = readableZipStream.getReader();
const pump = () =>
  reader
    .read()
    .then(() => {
      console.log('下载成功')
    })
    .catch((error) => {
      console.error('下载失败', error);
    })
pump();

经过简单的测试发现,streamSaver 的兼容性更佳,在一些非谷歌浏览器上,也能达到 2GB体积的下载,所以也是目前实现需求的首选方案。

其实上面两种技术方案拥有不止本文介绍的一些功能,还拥有其他强大的功能,感兴趣的同学可以去探索下。

其他注意事项不同的浏览器支持度不一样,需要多测试,并且考虑客户的接受程度;streamSaver 在本地因为证书问题,无法正常下载资源,可发布到测试服务器再验证;资源跨越问题需要自行解决。

本文正在参加「金石计划 . 瓜分6万现金大奖」

文章版权及转载声明:

作者:上网导航本文地址:https://www.90xe.com/post/5040.html发布于 2023-09-27
文章转载或复制请以超链接形式并注明出处技术导航

分享到:

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏