甲方客户甩来一个需求,需求把用户上传的视频、图片打包成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('').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浏览器支撑介绍:

纯前端 JS 实践批量打包并下载大文件
所以,为了统筹非谷歌浏览器的用户,还需求进一步地探究新的技能解决方案,也能够结合本公司对前端兼容性的要求来权衡。

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('');
        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体积的下载,所以也是目前实现需求的首选方案。

其实上面两种技能方案具有不止本文介绍的一些功用,还具有其他强大的功用,感兴趣的同学能够去探究下。

其他注意事项

  1. 不同的浏览器支撑度不一样,需求多测验,而且考虑客户的承受程度;
  2. streamSaver 在本地因为证书问题,无法正常下载资源,可发布到测验服务器再验证;
  3. 资源跨过问题需求自行解决。

本文正在参加「金石方案 . 分割6万现金大奖」