Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I revoke an object URL only after it's downloaded?

I'm saving a file in JavaScript using the following code:

var a = document.createElement('a');
a.href = URL.createObjectURL(new Blob(['SOME DATA']));
a.download = 'some.dat';
a.click();

I want to revoke the URL (using URL.revokeObjectURL) once the file is downloaded. When is it safe to do so?

Can I revoke it immediately after calling a.click() (which seems to work, but I'm not sure it's safe)? In a's click event listener? Is there a way to make a click event listener run after the default action?

like image 423
Steve Trout Avatar asked May 15 '16 16:05

Steve Trout


People also ask

How do you revoke a URL?

The URL. revokeObjectURL() static method releases an existing object URL which was previously created by calling URL. createObjectURL() . Call this method when you've finished using an object URL to let the browser know not to keep the reference to the file any longer.

Do you need to revokeObjectURL?

Usage notes revokeObjectURL() when you no longer need them. Browsers will release object URLs automatically when the document is unloaded; however, for optimal performance and memory usage, if there are safe times when you can explicitly unload them, you should do so.

How do I find my blob URL?

Right-click on the webpage and click “Inspect” in the menu. When the DevTools panel opens, click on the three vertical dots in the top-right corner and select “Undock into a separate window.” Press Ctrl + F on Windows or Cmd + F on Mac devices to find the blob URL. Enter “ blob:HTTP ” to find the link for the video.


2 Answers

a.click() on a DOM element simulates a click on the element, instead of propagation of the click event, so it's directly sent to the browser. I believe it would be a little bit safer to move revoking of URL object to another event cycle using a timer:

setTimeout(function() {
 URL.revokeObjectURL(a.href);
}, 0);
like image 119
Stanislav Šolc Avatar answered Oct 24 '22 15:10

Stanislav Šolc


After some experimenting, it seems both Chrome and Safari are able to download a file of 2GB just fine when revoking right after clicking an element. And Firefox was able to download a file of 600MB before the browser started grinding to a halt.

This is what I used to download large files:

const a = document.createElement('a');
const buffer = new ArrayBuffer(2_000_000_000);
const view = new Uint8Array(buffer);
for(let i=0; i<view.length; i++) {
    view[i] = 255;
}
a.href = URL.createObjectURL(new Blob([buffer]));
a.download = 'some.dat';
a.click();
URL.revokeObjectURL(a.href);

The spec doesn't specifically mention aborting existing streams when revoking a url, so in theory doing it like this would be just fine.

However, to be safe I would either revoke the url after a few seconds using setTimeout(), or if the download is initiated from a specific screen, you can add logic to revoke it once the user navigates away from that screen.

Browsers also automatically revoke object urls once the last page of your domain is closed, so depending on your situation, not revoking urls at all might also be a viable solution.

like image 40
Jespertheend Avatar answered Oct 24 '22 14:10

Jespertheend