Skip to content
Advertisement

How to generate a zip file synchronously using JSZip?

I’m working on a React.js application, i have a loop from j=1 to j=2000 and i want to download a zip file when j=1 or j=2000.

The problem is that the two zip files downloaded at the same time after the end of the loop. in other words the download of the two zip starts when j = 2000.

I tried to make the zip generation synchronous by using async and await, but it didn’t work for me.

const generateCollection = async ()=>{
    for(var j = 1; j <= 2000; j++){
      let zip = new JSZip();
      let metadata = zip.folder("metadata");
      const obj = {name: "Simple name", age: "Simple age"}
      metadata.file(`1.json`, JSON.stringify(obj, null, 4))

      console.log("Start Downloading: ", j)
      if(j===1 || j===2000){
        await zip.generateAsync({type:"blob"})
        .then(content=>{
          setIsLoading(false)
          FileSaver.saveAs(content, `collection_${j}.zip`);
          console.log("Saved...... ", j)
        })
      }
    }
 }

I will appreciate any help, or suggestion!!

Advertisement

Answer

The problem here is not with the generateAsync method, but rather with the saveAs, which is delayed until the cpu is available and cannot be awaited as reported here:

https://github.com/eligrey/FileSaver.js/issues/389

A solution could be to don’t await at all, but instead convert the loop into an async event to give the browser the time to show the save dialog between the iterations:

const generateCollection = ()=> {
    var j = 1;
    const loop = function() {
        if (j <= 2000) {
            let j2 = j; //Create a local copy of the loop var
            let zip = new JSZip();
            let metadata = zip.folder("metadata");
            const obj = {name: "Simple name", age: "Simple age"};
            metadata.file(`1.json`, JSON.stringify(obj, null, 4));
            
            console.log("Start Downloading: ", j)
            if (j2===1 || j2===2000){
                zip.generateAsync({type:"blob"})
                .then(content=>{
                    saveAs(content, `collection_${j2}.zip`);
                    console.log("Saved...... ", j2)
                });
            }
            j++;
            setTimeout(loop, 0);
        }
    };
    setTimeout(loop, 0);
}

$(function() {
        generateCollection();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.0/FileSaver.min.js"></script>

Note that the above code doesn’t work within the fiddle due to security restrictions, you have to put it somewhere else.

Advertisement