17

I'm trying to write a fail-safe program that uses the canvas to draw very large images (60 MB is probably the upper range, while 10 MB is the lower range). I have discovered long ago that calling the canvas's synchronous function toDataURL usually causes the page to crash in the browser, so I have adapted the program to use the toBlob method using a filler for cross-browser compatibility. My question is this: How long do Blob URLs using the URL.createObjectURL(blob) method last?

I would like to know if there's a way to cache the Blob URL that will allow it to last beyond the browser session in case somebody wants to render part of the image at one point, close the browser, and come back and finish it later by reading the Blob URL into the canvas again and resuming from the point at which it left off. I noticed that this optional autoRevoke argument may be what I'm looking for, but I'd like a confirmation that what I'm trying to do is actually possible. No code example is needed in your answer unless it involves a different solution, all I need is a yes or no on if it's possible to make a Blob URL last beyond sessions using this method or otherwise. (This would also be handy if for some reason the page crashes and it acts like a "restore session" option too.)

I was thinking of something like this:

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
  }
}

Note that I am not certain this will work the way I intend, so any confirmation would be awesome.

EDIT just realized that sessionStorage is not the same thing as localStorage :P

Patrick Roberts
  • 40,065
  • 5
  • 74
  • 116
  • I just tested pretty much exactly what this code is, and it appears to work when you refresh the page, but when the session is closed, the localStorage persists, but the blobURL does not... – Patrick Roberts Dec 20 '12 at 09:09
  • Patrick, what happens when you navigate away, then click the back button? – Jonathan F Dec 21 '12 at 05:02
  • Same thing as when you refresh the page, because it is still the same session. – Patrick Roberts Dec 22 '12 at 00:00
  • Hi @PatrickRoberts, I have a question here: https://stackoverflow.com/questions/67015438/how-to-keep-a-bloburl-from-localstorage-useful-even-if-browser-memory-and-sessio – Zedd Apr 09 '21 at 07:31

1 Answers1

15

Blob URL can last across sessions? Not the way you want it to.

The URL is a reference represented as a string, which you can save in localStorage just like any string. The location that URL points to is what you really want, and that won't persist across sessions.

When using URL.toObjectUrl() in conjuction with the autoRevoke argument, the URL will persist until you call revokeObjectUrl or "till the unloading document cleanup steps are executed." (steps outlined here: http://www.w3.org/TR/html51/browsers.html#unloading-document-cleanup-steps)

My guess is that those steps are being executed when the browser session expires, which is why the target of your blobURL can't be accessed in subsequent sessions.

Some other discourse on this: How to save the window.URL.createObjectURL() result for future use?

The above leads to a recommendation to use the FileSystem API to save the blob representation of your canvas element. When requesting the file system the first time, you'll need to request PERSISTENT storage, and the user will have to agree to let you store data on their machine permanently.

http://www.html5rocks.com/en/tutorials/file/filesystem/ has a good primer everything you'll need.

Community
  • 1
  • 1
Jonathan F
  • 1,995
  • 12
  • 18
  • Those *document cleanup steps* seem to happen on every *document unload*, which is far before a session expires. – Bergi Dec 21 '12 at 03:05
  • 1
    @Bergi Thats what I would have thought from reading the docs, but according to Patrick it works when you refresh the page. My guess is that modern browsers prevent those unload steps until the window unloads(maybe thats whats behind CTR+ALT+T bringing back the last closed tab so well?). – Jonathan F Dec 21 '12 at 03:23
  • Looks like its up to the `Browsing Context` to determine when to unload a particular `Document` is unloaded(unless the user forces it): http://www.w3.org/TR/html51/browsers.html#garbage-collection-and-browsing-contexts – Jonathan F Dec 21 '12 at 03:26
  • Yeah, I'm sure there are optimisations; especially for a quick page reload. But that does not mean you should not rely on them to work :-) – Bergi Dec 21 '12 at 03:28
  • I agree. Looking further into it, the spec requires user agents to execute these steps whenever the page is navigated. I first thought the information may be kept as a part of the option state object associated with a browsing context's history. It may be there, but the File API spec's clearly state that a user agent must revoke the URL on unload. I wasn't able to find references on how a refresh is treated in regards to unloading. It may be that a **prompt to unload** is called, but not the subsequent unload. – Jonathan F Dec 21 '12 at 05:01
  • Thank you for your answer involving the FileSystem API. I have already looked into it, and plan to use it. The only drawback is for the `requestQuota`, I'll need to request about 50-100 MB if I want the blob to be properly cached, which is why I was hoping the `autoRevoke` argument on the `createObjectURL` method would be a sufficient shortcut. – Patrick Roberts Dec 22 '12 at 00:04
  • @JonathanF, I have a question here: https://stackoverflow.com/questions/67015438/how-to-keep-a-bloburl-from-localstorage-useful-even-if-browser-memory-and-sessio – Zedd Apr 09 '21 at 07:37