一个 Blob 会持续多久?

24

我正在尝试编写一个安全失败的程序,使用画布绘制非常大的图像(60 MB可能是上限,而10 MB则是下限)。我很久以前就发现调用画布的同步函数toDataURL通常会导致浏览器崩溃,因此我已经改用了toBlob方法,并使用填充物来实现跨浏览器兼容性。我的问题是:使用URL.createObjectURL(blob)方法创建的Blob URL可以持续多长时间?

我想知道是否有一种缓存Blob URL的方法,使其在浏览器会话结束后仍然存在,以便某人在某个时间点渲染图像的某个部分,关闭浏览器,然后通过将Blob URL读入画布再次开始,并从离开时的点继续完成它。我注意到这个可选的autoRevoke参数可能是我正在寻找的,但我想确认一下我所尝试做的事情是否实际上是可能的。不需要在您的答案中提供代码示例,除非它涉及不同的解决方案,我只需要回答是否可以使用此方法或其他方法使Blob URL持续存在于会话之间。(如果页面崩溃并像“恢复会话”选项一样运行,这也将非常有用。)

我正在考虑像这样的东西:

function saveCache() {
  var canvas = $("#canvas")[0];
  canvas.toBlob(function (blob) {
    /*if I understand correctly, this prevents it from unloading
      automatically after one asynchronous callback*/
    var blobURL = URL.createObjectURL(blob, {autoRevoke: false});
    localStorage.setItem("cache", blobURL);
  });
}

//assume that this might be a new browser session

function loadCache() {
  var url = localStorage.getItem("cache");
  if(typeof url=="string") {
    var img = new Image();
    img.onload = function () {
      $("#canvas")[0].getContext("2d").drawImage(img, 0, 0);
      //clear cache since it takes up a LOT unused of memory
      URL.revokeObjectURL(url);
      //remove reference to deleted cache
      localStorage.removeItem("cache");
      init(true); //cache successfully loaded, resume where it left off
    };
    img.onprogress = function (e) {
      //update progress bar
    };
    img.onerror = loadFailed; //notify user of failure
    img.src = url;
  } else {
    init(false); //nothing was cached, so start normally
  }
}

请注意,我不确定这将按照我预期的方式工作,因此任何确认都将是很棒的。

编辑刚刚意识到sessionStoragelocalStorage不是同一件事:P


我刚刚测试了这段代码,基本上就是这样的,当你刷新页面时它似乎可以工作,但当会话关闭时,localStorage仍然存在,但blobURL不再存在... - Patrick Roberts
Patrick,当你导航离开后,然后点击返回按钮会发生什么? - freethejazz
因为它仍然是同一个会话,所以与刷新页面时的情况相同。 - Patrick Roberts
1个回答

22

Blob URL可以跨会话持久保存吗?不是你想要的那种方式。

URL是一个表示为字符串的引用,您可以像任何字符串一样将其保存在localStorage中。URL指向的位置才是您真正想要的,而这个位置不会跨会话持久保留。

当使用URL.toObjectUrl()结合autoRevoke参数时,URL将持久存在,直到您调用revokeObjectUrl或“执行卸载文档清理步骤”(在此处概述: http://www.w3.org/TR/html51/browsers.html#unloading-document-cleanup-steps

我猜测当浏览器会话过期时,执行了这些步骤,这就是为什么您的 blobURL 的目标不能在后续会话中访问的原因。

有关此问题的其他讨论:如何保存window.URL.createObjectURL()结果以供将来使用?

以上导致建议使用FileSystem API保存画布元素的blob表示形式。第一次请求文件系统时,您需要请求PERSISTENT存储,并且用户必须同意让您永久存储数据在他们的计算机上。

http://www.html5rocks.com/en/tutorials/file/filesystem/有一个很好的指南,包括您需要的所有内容。


那些“文档清理步骤”似乎会在每个“文档卸载”时发生,而这比会话过期要早得多。 - Bergi
1
@Bergi 从文档中我也是这么认为的,但根据Patrick的说法,在刷新页面时它是有效的。我猜现代浏览器会阻止这些卸载步骤直到窗口卸载(也许这就是为什么CTR+ALT+T能够很好地恢复最后关闭的标签页的原因?)。 - freethejazz
看起来由“浏览上下文”决定何时卸载特定的“文档”(除非用户强制执行):http://www.w3.org/TR/html51/browsers.html#garbage-collection-and-browsing-contexts - freethejazz
是的,我确定有优化方法;特别是对于快速页面重新加载。但这并不意味着你不应该依赖它们来工作 :-) - Bergi
我同意。进一步研究后,规范要求用户代理在每次导航页面时执行这些步骤。我最初认为信息可能作为与浏览上下文历史记录相关联的选项状态对象的一部分保存。它可能存在,但是文件API规范明确指出用户代理必须在卸载时撤销URL。我无法找到有关如何处理刷新以及卸载的参考资料。可能会调用提示卸载,但不会调用随后的卸载。 - freethejazz
感谢您提供有关FileSystem API的答案。我已经研究过它,并计划使用它。唯一的缺点是对于requestQuota,如果我想要正确缓存blob,我需要请求大约50-100 MB,这就是为什么我希望createObjectURL方法中的autoRevoke参数可以成为一个足够的快捷方式的原因。 - Patrick Roberts

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接