Recently there is a need to achieve a number of files after batch compression batch download.

My first reaction was to compress the generated file on the server side, generate a new URL to return to the front end, and open a new window to download.

The downside is that when there are too many files:

  1. The back-end implementation is complex.
  2. The server resource usage is too high. Too many function modules or files are accessed.
  3. The front end needs rotation training to wait for the completion of the background packaging, and the logic is complicated.
  4. The client simply closes the browser and the server is still packaged, wasting resources

.

So I thought, can I ZIP on the browser side? A plugin named “JSZip” has been created by searching for browser compression keywords.

Download files using the Fetch API

/** * Use fetch to download a single file * return objects containing file names and binary Blob objects ** /
      const download = (url) = >  fetch(url).then((res) = > ({
          name: url.substring(url.lastIndexOf("/") + 1, url.length),
          blob: res.blob(),
        }));
Copy the code

Use the browser Fetch to download the file, return the “blob object” and process the file name.

Use promise.all for multiple file downloads

    const downLoadGroup = urls= > Promise.all(urls.map(download))
Copy the code

When using promise.all directly, multiple GET requests will be made at the same time, which happens to be a lot of people using bulk downloads, which will put a lot of strain on the server. Group requests into groups of 5 or 10 downloads and make promise.all requests. One group is followed by another, greatly reducing the strain on the server. Extending the Promise prototype method with “BluebirdJS” eliminates the need to do this manually, using the promise.map method for grouping.

      /** * Extend Promise with bluebird extension method * optimize GET request */
      const downloadGroup = (urls, group_size) = > {
        return Promise.map(urls, async (url) => await download(url), {
          concurrency: group_size,
        });
      };
Copy the code

Use JSZip for file compression

    /** * Use JSZip to compress files * use BLOb mode * Use FileSaver to download */
      const generateZIP = async (files) => {
        const zip = new JSZip();
        files.forEach((item) = > {
          zip.file(item.name, item.blob, { binary: true });
        });
        const content = await zip.generateAsync({ type: "blob" });
        const currentDate = new Date().getTime();
        const fileName = `zipped-${currentDate}.zip`;
        return saveAs(content, fileName);
      };
Copy the code

Download the demo

“JSZip Demo”