Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is it safe to call URL.revokeObjectURL?

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

  1. 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?

  2. 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?

like image 379
gman Avatar asked Feb 02 '16 18:02

gman


1 Answers

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.

like image 189
gman Avatar answered Sep 30 '22 08:09

gman