Browser is cancelling multiple file download requests

Viewed 962

I am trying to download multiple files that the user has selected for download. However, the browser is cancelling all but last download request. If I am increasing the delay between the requests to say about 1 second, then those files get downloaded, but even in this case, sometimes some files are missed. The files are being downloaded from amazon s3 urls(i.e. these are CORS).

I am doing this by creating an anchor element with the url and then calling the click event on it using javascript.

downloadFile(url) {
    let a = document.createElement('a');
    a.id = url;
    // a.setAttribute('target', 'blank');
    a.download = '';
    a.href = url;
    // firefox doesn't support `a.click()`...
    // console.log('dowmloading ' + url);
    a.dispatchEvent(new MouseEvent('click'));
    a.remove();
}

Then on download button click event I'm doing this:

let delay = 0;
        urlList.forEach(url => {
            return setTimeout(downloadFile.bind(null, url), 100 * ++delay);
        });

Is there a way to accomplish this?

Why is the browser cancelling the requests?

2 Answers

Why is the browser cancelling the requests?

Because you are essentially "canceling navigation" by clicking the next link, before the browser is fully done with what it has to do when you clicked the previous one.

If this weren’t downloads, but regular links to pages, then this is the behavior you want - if the user clicks a link to page A first, but then looses patience and clicks on another link to page B, then the request for page A gets cancelled at that point - no need in loading two resources, when only one can be displayed at the same time anyway.

I don’t think there is much you can do about this, if you do not want to figure out a "magic number" of a timeout that somehow makes it "work" - especially since you won’t know if that works in general, or maybe just on your machine, with your internet connection, etc.

I am trying to download multiple files that the user has selected for download.

You could have those selected files wrapped into a container format - like for example ZIP (more than just a "container", strictly speaking) - dynamically on the server, so that the user just has to download one file only (which they will then have to unpack again on their own machine.)

Or you change your file selection process to begin with. Instead of having the user mark the files they want using checkboxes or something like that, present them direct links to the files instead maybe? Then they can click each one they want one after another, and the "normal" download functionality will take place.

@misorude is right about why they're getting canceled but a workaround is to use an iframe instead of an anchor tag to download a file.

a typescript implementation of a download file below:

export function downloadFile(downloadLink: string): void {
  const iframe = document.createElement("iframe");
  iframe.setAttribute("sandbox", "allow-downloads allow-scripts");
  iframe.src = downloadLink;
  iframe.setAttribute("style", "display: none");

  document.body.appendChild(iframe);
}

So it's similar to your implementation - only thing is, you'll have stray (non-displayed) iframes on you DOM. There's no way to tell when the iframe is done downloading the file so there isn't an adequate way to know when to remove them. But at least you wouldn't get your network requests canceled.

Related