If I understand correctly URL.createObjectURL
creates a URL that represents a file or a blob. Because the URL is just a string the browser has no way to know when you're finished with the resource that URL represents so there's a provided URL.revokeObjectURL
function.
MDN shows this example:
var canvas = document.getElementById("canvas"); canvas.toBlob(function(blob) { var newImg = document.createElement("img"); var url = URL.createObjectURL(blob); newImg.onload = function() { // no longer need to read the blob so it's revoked URL.revokeObjectURL(url); }; newImg.src = url; document.body.appendChild(newImg); });
So some questions
Would it be safe to change the code to revoke the URL immediately after assigning newImg.src
?
var canvas = document.getElementById("canvas"); canvas.toBlob(function(blob) { var newImg = document.createElement("img"); var url = URL.createObjectURL(blob); newImg.src = url; // no longer need to read the blob as it's assigned to newImg.src URL.revokeObjectURL(url); document.body.appendChild(newImg); });
I'm guessing the answer is "no" because potentially nothing has started on newImg.src = url;
. It's still just a string at that point and will remain so until the current JavaScript event exits. Or is it?
Would it be valid/legal/correct to revoke the URL but still use it knowing it's referenced by other objects?
var canvas = document.getElementById("canvas"); canvas.toBlob(function(blob) { var newImg = document.createElement("img"); var url = URL.createObjectURL(blob); newImg.onload = function() { // no longer need to read the blob so it's revoked URL.revokeObjectURL(url); // Use the URL again even though it's revoked var newImg2 = new Image(): newImg2.src = url; }; newImg.src = url; document.body.appendChild(newImg); });
In this case I'm assigning newImg2.src = url
even though I've already revoked the URL. The idea being that newImg
is still referencing the blob URL so it would seem valid to be able to say
someImage.src = someOtherImage.src
at any time. Is it?
Okay, well, following @adeneo's advice I tested this
$('#test').on('change', function(e) { var newImg = document.createElement("img"); var url = URL.createObjectURL( e.target.files[0] ) console.log(url); newImg.src = url; URL.revokeObjectURL(url); document.body.appendChild(newImg); console.log(url); }); $('#test3').on('change', function(e) { var newImg = document.createElement("img"); var url = URL.createObjectURL( e.target.files[0] ) console.log(url); newImg.src = url; newImg.onload = function() { URL.revokeObjectURL(url); document.body.appendChild(newImg); var i = new Image(); i.src= newImg.src; document.body.appendChild(i); setTimeout(function() { var g = new Image(); g.src = newImg.src; document.body.appendChild(g); }, 3000); } });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <p>test revoke before use</p> <input type="file" id="test"/> <br /> <br /> <br /> <p>test use revoke use</p> <input type="file" id="test3" />
At least in Firefox, once URL.revokeObjectURL
is called the URL can no longer be used, even though other things are accessing it.
So both #1 and #2 in the question fail and, even though in #2 newImg.src
still has the URL that URL won't work anywhere else once URL.revokeObjectURL
has been called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With