I'm developing a small application that allows the user to select some documents on the frontend and when they click "Download" a zip is being generated with all their documents.
I'm using client-zip for that. It all works fine with 1 document (1 fetch), but there's one small issue, I can't figure out. How can I add dynamic fetches based on the number of elements in an array?
My code so far:
const allDownloads = [];
async function downloadTestZip() {
const code = await fetch(allDownloads[0]);
const blob = await downloadZip([code]).blob();
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'test.zip';
link.click();
link.remove();
}
The allDownloads=[] is filled when the user checks the checkmark next to the document. So there can be up to 200 different docs.
You have to create an array of Promises, and then await them all :
const promises = allDownloads.map( url => fetch(url) ); // or simply .map(fetch), as a shorthand
const codes = await Promise.all(promises);
// now codes is an array of codes (strings, probably?)
To improve latency, you can use an async iterator (client-zip is happy to take that instead of an array).
async function *lazyFetch() {
for (const url of allDownloads) yield await fetch(url)
}
const blob = await downloadZip(lazyFetch()).blob()
Functionally it does the same thing as the solution with Promise.all (and it's barely more code). However, client-zip will be able to start processing the data as soon as the first fetch Response is ready (instead of all 200 of them).
Creating the ZIP file involves some computations and copying. So if you let client-zip start early, all that CPU-intensive stuff can happen while the browser is handling the HTTP request for the next file. Browsers typically have a pool of HTTP clients and they won't start 200 requests concurrently.