Reputation: 505
I'm having a problem while trying to make an extension. What the extension does is pretty simple, I have a URL with a ser of images, i get the src of all the images, and then use the Downloads API of chrome to download them on a folder. I have it, and works great, but there is a problem, all the downloads start consecutively, which constantly makes some downloads to fail, so i tried to make Chrome wait until a download has completed to start another.
First i tried to search if the Downloads API has a way to verify this, but, at least from what i've searched, i haven't find a method to get the DownloadItem, there is only two ways to do this, with search and the own download method, but both use a callback that seems to be asynchronous, then i tried to add a while before the download, and change it's condition with the one of those methods, but alway loops itself because while it's in the while loop, doesn't continue the callback of them, same with global methods like handleChanged(). So, how could i make Chrome wait until a download has ended before starting another without looping itself?
This is the part of the code i use for the downloads
for(let i=0; i<images.length; i++) {
// Download image
while(currentDownload) {
if (cont == 10000000) {
currentDownload = false;
} else {
cont = cont + 1;
}
};
cont = 0;
currentDownload = true;
var downloadUrl = images[i].split(" . ")[0];
img = images[i].split(" . ")[1];
console.log(name+"/"+img);
var downloading = chrome.downloads.download({
url: downloadUrl,
filename: name+"/"+img,
conflictAction: 'uniquify'
});
}
I put a counter on the while because the looping of my other tests were making my browser to crash, but it's better if there is a way to check until the download has ended before starting the next one. This is the listener i'm using to make the changes, just to be clear, i tried to put the search method on the prev code, even inside the while, and it just didn't worked. currentDownload is a global var.
function handleChanged(delta) {
//if (urlRegexD.test(pest)) {
if (delta.state && delta.state.current === "complete") {
console.log(`Download ${delta.id} has completed.`);
currentDownload = false;
}
//}
}
chrome.downloads.onChanged.addListener(handleChanged)
Upvotes: 4
Views: 5510
Reputation: 73526
Callbacks:
Extract one "step" into a function and invoke it from onChanged event listener.
function downloadSequentially(urls, callback) {
let index = 0;
let currentId;
chrome.downloads.onChanged.addListener(onChanged);
next();
function next() {
if (index >= urls.length) {
chrome.downloads.onChanged.removeListener(onChanged);
callback();
return;
}
const url = urls[index];
index++;
if (url) {
chrome.downloads.download({
url,
}, id => {
currentId = id;
});
}
}
function onChanged({id, state}) {
if (id === currentId && state && state.current !== 'in_progress') {
next();
}
}
}
Usage: downloadSequentially(arrayOfStringUrls, () => console.log('done'))
async/await:
Wrap the API calls in Promise and await them.
async function downloadSequentially(urls) {
for (const url of urls) {
if (!url) continue;
const currentId = await download(url);
const success = await onDownloadComplete(currentId);
}
}
function download(url) {
return new Promise(resolve => chrome.downloads.download({url}, resolve));
}
function onDownloadComplete(itemId) {
return new Promise(resolve => {
chrome.downloads.onChanged.addListener(function onChanged({id, state}) {
if (id === itemId && state && state.current !== 'in_progress') {
chrome.downloads.onChanged.removeListener(onChanged);
resolve(state.current === 'complete');
}
});
});
}
Usage: await downloadSequentially(arrayOfStringUrls)
- inside an async
function.
Upvotes: 10