3
votes

I am trying to get our web app to cache and display images for offline mode, while the storage part is done (default to IndexedDB and fallback to WebSQL for certain device), I am unsure if:

  1. Canvas or XHR is the better option to get image data.

  2. Blob or ArrayBuffer is the better option to store image data.

  3. Whether there are alternatives to these 2 questions I am not aware of.

There are many discussion on stackoverflow surrounding similar topics (Ref 1, 2). But a lot of them were asked in 2012, when FileSystem API was not deprecated and IndexedDB support were not widespread.

It's now 2014. I want to work towards a definitive/best practice answer for IndexedDB storage, with some considerations for WebSQL. Below are my research (as of 2014.09):

For Q1:

  • Canvas method has the advantage of no extra request, but toBlob method is not supported by most browser, conversion between dataUrl and Blob are likely CPU intensive. In addition we will lose image metadata and need to handle cross origin issues.

  • XHR method avoid canvas's drawbacks but introduce an extra request for every image, unless they are already cached by browser. The main advantage being modern browsers with xhr2 support can return binary response as Blob or ArrayBuffer natively.

For Q2:

  • Generally speaking, if you are not working on manipulating binary data, then Blob is the better choice, especially for image caching and display, since you need to call .createObjectURL with Blob anyway.

  • But Chrome has buggy support for Blob type in IndexedDB (fixed in Chrome 38, which is not released yet), and for WebSQL a common solution is to use base64. Both of which suggest ArrayBuffer might be the more compatible choice.

Notes on other potential solutions:

  • localStorage isn't a good fit for content image storage given its 5MB cap. Other problem including synchronous api (blocking IO) and no native support for binary content.

  • appcache would be great for static asset (where resource url are known), but for content image caching they are a headache to manage.

I haven't been able to locate a discussion/article that fully consider compatibility and performance of each choice. Can stackoverflow community help me out?


Update:

For what it's worth, I decide to go with XHR + Blob combination. My main reasoning:

  1. Simplicity: with XHR2 retrieving blob is as easy as setting xhr.responseType = 'blob'

  2. Native: the entire process is based on native api, from XHR Blob, to storing Blob in IndexedDB, to generating Object URL for image display. It might not necessarily imply better performance, but it certainly reduce needs for data conversion in application code.

  3. Design: image caching is not critical to our service, so I decide to support only browser with proper IndexedDB and XHR2.

1
You mention indexedDB and haven't mentioned plain-old-localStorage. Does that mean you have a large quantity of images and you've eliminated using localStorage to save your images in compressed .jpg format? - markE
@markE yes, localStorage's 5MB limit won't be enough for my use-case (high resolution content image caching). And given its synchronous api, would be a problem when read/writes are frequent. - bitinn
What about encoding your image into a dataUrl string using the fileReader API ? - laurent
@laurent will not be more efficient than blob or arraybuffer. - bitinn

1 Answers

-1
votes

You seem to be quick to disregard AppCache, that is built exactly for your use case. Yes, the Manifest is not the easiest feature to use, but the functionality is exactly what you need.

You mention that it's hard to manage the Manifest file. But if you can generate a list of files to be stored offline for your custom solution, you can use the same logic to dynamically generate a Manifest file. Just make sure your Manifest file is not a static file, but generated using the server-side language of your choice.

It seems natural to me that reimplementing a big entire feature of a browser will always be trickier than to use something that's built-in, so give AppCache another try. The browser support is also much wider.