问题
I'm using the library JSZip to create .png files and add them to a zip archive to be downloaded. The problem comes when I add too many large files.
I use a set of for loops to add the files to the zip then activate an automatic download. The issue seems to be that the download starts before the files have been updated so they end up with no data.
for (var row = 0; row < 3; row++) { // Loop for rows
for (var col = 0; col < 3; col++) { // Loop for cols
if (cropSrc[row][col]) { // If data for cropped img exists
var fileName = row + "" + col + ".png";
zip.file(fileName, cropSrc[row][col].src, {
base64: true
}); // Add file to zip
zip.file(fileName).async("uint8array").then(function(u8) { // Once file is complete... I think
console.log("done");
});
}
}
}
// Download zip file
zip.generateAsync({
type: "base64"
}).then(function(base64) {
window.location = "data:application/zip;base64," + base64;
});
I have to make sure I wait till all files have been updated before downloading, how would I do this using async functions?
Here is JSZip Async Documentation
Not sure if this will help but here is a more complete look at the full code, I'm using SAPUI5 and developing in SAP Web IDE:
var cropSrc = {
0: {
0:{src:"base64 data placeholder"},
1:{src:"base64 data placeholder"},
2:{src:"base64 data placeholder"}
},
1: {
0:{src:"base64 data placeholder"},
1:{src:"base64 data placeholder"},
2:{src:"base64 data placeholder"}
},
2: {
0:{src:"base64 data placeholder"},
1:{src:"base64 data placeholder"},
2:{src:"base64 data placeholder"}
}
};
sap.ui.define([
"sap/ui/core/mvc/Controller",
"SAP_SARAH_ML_Project/libs/jszip", // Enables the jszip library (imports)
], function(Controller, jszipjs) { // Second part of importing
"use strict";
return Controller.extend("SAP_SARAH_ML_Project.controller.View1", {
zipImg: function() {
for (var row = 0; row < 3; row++) { // Loop for rows
for (var col = 0; col < 3; col++) { // Loop for cols
if (cropSrc[row][col]) { // If data for cropped img exists
var fileName = row + "" + col + ".png";
zip.file(fileName, cropSrc[row][col].src, {
base64: true
}); // Add file to zip
zip.file(fileName).async("uint8array").then(function(u8) { // Once file is complete... I think
console.log("done");
});
}
}
}
// Download zip file
zip.generateAsync({
type: "base64"
}).then(function(base64) {
window.location = "data:application/zip;base64," + base64;
});
}
});
});
回答1:
You can use Promise.all for this:
let arr = [addFilePromise('file1'),addFilePromise('file2'),addFilePromise('file3')]
Promise.all(arr).then(zip.generateAsync({type:"base64"}))
EDIT:
let fileAddActions = [];
let addFilePromise = function(filename){
zip.file(fileName, cropSrc[row][col].src, {
base64: true
});
return zip.file(fileName).async("uint8array")
}
for (var row = 0; row < 3; row++) { // Loop for rows
for (var col = 0; col < 3; col++) { // Loop for cols
if (cropSrc[row][col]) { // If data for cropped img exists
var fileName = row + "" + col + ".png";
fileAddActions.push(addFilePromise(fileName))
}
}
}
Promise.all(fileAddActions).then(zip.generateAsync({type:"base64"})).then(base64 => {
indow.location = "data:application/zip;base64," + base64;
})
something like this should work, also i recommend this article: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Promise
回答2:
Since async returns a Promise, you can make the function where you are doing the for loop an async/await function
async functionName() {
for loop...
let res = await zip.file(fileName).async("uint8array");
}
来源:https://stackoverflow.com/questions/51638789/wait-for-all-files-to-update-then-download-them