什么时候调用URL.revokeObjectURL是安全的?

gma*_*man 21 javascript html5

如果我理解正确,则URL.createObjectURL创建表示文件或blob的URL.因为URL只是一个字符串,所以浏览器无法知道您何时完成了URL所代表的资源,因此提供了一个URL.revokeObjectURL函数.

MDN显示了这个例子

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);
});
Run Code Online (Sandbox Code Playgroud)

所以有些问题

  1. 在分配后立即更改代码以撤销URL是否安全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);
    });
    
    Run Code Online (Sandbox Code Playgroud)

    我猜测答案是"不",因为可能没有任何事情开始newImg.src = url;.它仍然只是一个字符串,并将保持这样,直到当前的JavaScript事件退出.或者是吗?

  2. 撤销URL是否有效/合法/正确但是知道它被其他对象引用仍然使用它吗?

    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);
    });
    
    Run Code Online (Sandbox Code Playgroud)

    在这种情况下,newImg2.src = url即使我已经撤销了URL,我仍在分配.这个想法newImg仍然是引用blob URL,所以它似乎是有效的

    someImage.src = someOtherImage.src
    
    Run Code Online (Sandbox Code Playgroud)

    随时.是吗?

gma*_*man 5

好吧,按照@adeneo的建议,我对此进行了测试

$('#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);
    }
});
Run Code Online (Sandbox Code Playgroud)
<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" />
Run Code Online (Sandbox Code Playgroud)

至少在Firefox中,URL.revokeObjectURL即使有其他东西正在访问它,一旦被调用,URL就无法再使用。

因此,问题1和问题2都失败了,即使问题2 newImg.src中的URL仍然存在,一旦URL.revokeObjectURL调用该URL,该URL在其他任何地方都将不起作用。