Reputation: 2239
I'm building a Chrome extension to download a series of files from a site. The downloading function is derived from How to save a file from a URL with JavaScript.
The program structure is like:
function download()
{
while(there are still files to download)
{
saveFile(url);
}
}
But I find that all the files are actually written to disk at once after download()
returns. And the addresses of those files start with blob:
when examine from Chrome's downloads manager.
I wonder if I make the call to saveFile
asynchronously, those files could be written one at a time.
Upvotes: 2
Views: 16579
Reputation: 140220
Using promises, which are available in Chrome out of the box, you can define the functions like so:
// Download a file form a url.
function saveFile(url) {
return new Promise(function(resolve, reject) {
// Get file name from url.
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function() {
resolve(xhr);
};
xhr.onerror = reject;
xhr.open('GET', url);
xhr.send();
}).then(function(xhr) {
var filename = url.substring(url.lastIndexOf("/") + 1).split("?")[0];
var a = document.createElement('a');
a.href = window.URL.createObjectURL(xhr.response); // xhr.response is a blob
a.download = filename; // Set the file name.
a.style.display = 'none';
document.body.appendChild(a);
a.click();
return xhr;
});
}
function download(urls) {
return Promise.all(urls.map(saveFile));
}
Using it:
download.then(function() {
alert("all files downloaded");
}).catch(function(e) {
alert("something went wrong: " + e);
});
If you want to wait for 1 file to download before proceeding with next, the download function should be written like:
function download(urls) {
var cur = Promise.resolve();
urls.forEach(function(url) {
cur = cur.then(function() {
return saveFile(url);
});
});
return cur;
}
Usage is same as before.
Upvotes: 9