I was reminded of this question.. since it has no answers yet, I write a possible solution in case it can be useful to someone else:
- as said, the first problem is with passing blob url to jszip (it does not support blobs but it also does not throw any error to notify that and it successfully generates an archive of corrupted files): to correct this, simply pass a base64 string of the data instead of its blob object url;
- the second problem is with file name synchronization: the easiest workaround here is to download one file at a time instead of using parallels xhr requests.
So, the modified upper code can be:
var fileURLs = ['http://www.test.com/img.jpg',...];
var zip = new JSZip();
var count = 0;
downloadFile(fileURLs[count], onDownloadComplete);
function downloadFile(url, onSuccess) {
var xhr = new XMLHttpRequest();
xhr.onprogress = calculateAndUpdateProgress;
xhr.open('GET', url, true);
xhr.responseType = "blob";
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (onSuccess) onSuccess(xhr.response);
}
function onDownloadComplete(blobData){
if (count < fileURLs.length) {
blobToBase64(blobData, function(binaryData){
// add downloaded file to zip:
var fileName = fileURLs[count].substring(fileURLs[count].lastIndexOf('/')+1);
zip.file(fileName, binaryData, {base64: true});
if (count < fileURLs.length -1){
count++;
downloadFile(fileURLs[count], onDownloadCompleted);
}
else {
// all files have been downloaded, create the zip
var content = zip.generate();
// then trigger the download link:
var zipName = 'download.zip';
var a = document.createElement('a');
a.href = "data:application/zip;base64," + content;
a.download = zipName;
a.click();
}
});
}
}
function blobToBase64(blob, callback) {
var reader = new FileReader();
reader.onload = function() {
var dataUrl = reader.result;
var base64 = dataUrl.split(',')[1];
callback(base64);
};
reader.readAsDataURL(blob);
}
function calculateAndUpdateProgress(evt) {
if (evt.lengthComputable) {
...
}
}
Last note, this solution works quite well if you download few and little files (about less than 1MB as whole size for less than 10 files), in other cases JSZip will crash the browser tab when the archive is going to be generated, so it will be a better choice to use a separated thread for compression (a WebWorker, like zip.js does).
If after that the archive has been generated, the browser still keeps crashing with big files and without reporting any errors, try to trigger the saveAs window without passing binary data, but by passing a blob reference (a.href = URL.createObjectURL(zippedBlobData);
where zippedBlobData
is the blob object that refers to the generated archive data);