This presentation is an HTML5 website

Press -> key to advance.

Zoom in/out: Ctrl or Command + +/-

Having issues seeing the presentation? Read the disclaimer

1

Offline, And On

Application Caching,
Client-Side Storage,
and You

Michael Mahemoff
@Mahemoff
Google Developer Relations

2
The web is fundamentally online
"Offline Web App"===oxymoron
Right?
Apps these days are rich

Online, To Off

  • fully offline apps
  • online-offline
Don't just think website
Think desktop
Think mobile

What if they required 24x7 connectivity, everywhere?

What if you had to download them every time you used them?

Not ubiquitous
Not there yet :(
Even in the City
Counterpoint: "You're Not on a efffing Plane (and if you are, it doesn't matter)!"
- David Hansson
Connections break
Phones drop out
This shouldn't determine if you can do your job or not
Fine, net everywhere. Now what?

The App

The Data

Loading still takes time

Latency hurts

Offline App, Offline Data
Application Cache
But don't we already have a cache?
HTML5: Reinventing the hacks of yore
**Application** Cache
http://3.ly/timer
Visit, go offline, visit again

Application Cache

HTML:
<html manifest="timer.manifest">
timer.manifest:
CACHE MANIFEST
timer.html
timer.css
timer.js
.htaccess:
AddType text/cache-manifest manifest

Application Cache - Tighter Spec

CACHE MANIFEST
# version 17.0.1
 
CACHE:
stockApp.html
stockApp.js
stockApp.css
 
FALLBACK:
/stocks/* sorry.html
 
NETWORK:
/prices/*

Application Cache - Tighter Control

Monitor cache state
alert(window.applicationCache.status);
window.applicationCache.addEventListener("cached", onAppCached, false);
Initiate downloading
window.applicationCache.update();
"Hot swap" the cache
window.applicationCache.swapCache();
The "URLs on Plane" Problem
Installable Web Apps: The Chrome Web Store
Installed and "Feels" installed
WebOS
Adobe Air
PhoneGap
Native Look and Feel - Sencha Touch, JQTouch, ...

http://3.ly/timer
Try it in your phone

http://3.ly/timer
Mobile Bookmark Bubble

Android too

Offline Storage

http://3.ly/timer
Also using offline storage

Storage: A not so accurate history
Cookies
Plugin-based storage
Global Storage
window.name
File Access
Gears
Web Storage
Web SQL Database
IndexedDB
File

The Veritable Cookie

var username = document.querySelector('#username');
  // place content from previous edit
  if (!username.value) {
    var keyValues = document.cookie.split(";");
    for (var i=0; i<keyValues.length; i++) {
      var keyValue=keyValues[i].split('=');
      if (keyValue[0].replace(/^ +/,"")=='value') username.value = keyValue[1];
    }
  }
 
  // save content in cookie
  username.addEventListener('keyup', function () {
    document.cookie = 'value='+username.value;
    console.log(document.cookie, "--", username, username.value);
  }, false);

Use case: Save username

A pre-HTML5 hack
Meet the New(-ish) Kids on the Block
  • Web Storage
  • Web SQL Database
  • IndexedDB
  • File

Web Storage

// use localStorage for persistent storage
// use sessionStorage for per tab storage
var area = document.getElementById("area");

area.addEventListener('keyup', function () {
  localStorage['value'] = area.value;
}, false);
area.value = localStorage['value'];

Crash-Safe Mail Client: Save drafts locally

Web Storage

  • localStorage
  • sessionStorage

Web Storage

  • ✔ Easy
  • ✔ Well supported by browsers
  • ✘ Not structured, no indexing
  • ✘ No locking/transactions
Web SQL Storage
html5rocks.webdb.db = openDatabase("Todo", "1.0", "Todo manager", dbSize);
db.transaction(function(tx) {
  tx.executeSql("CREATE TABLE IF NOT EXISTS todo(ID INTEGER PRIMARY KEY ASC,
                 todo TEXT, added_on DATETIME)", []);
  tx.executeSql("INSERT INTO todo(todo, added_on) VALUES (?,?)", 
        [todoText, addedOn], function() {
          html5rocks.webdb.showAllTodoItems(loadTodoItems); // success
        }, html5rocks.webdb.onError); //failure
});
Web SQL Storage
  • ✔ Structured
  • ✔ Transactions
  • ✔ Async and Sync
  • ✘ Complex
  • ✘ Not in IE or Firefox
  • ✘ Standard in limbo

Indexed Database

Offline Storage - Indexed Database

var db = indexedDB.open('tweets', 'Tweet store', false);
db.createObjectStore('tweets', 'id'); // 'id' is the key
db.createIndex('ByScreenname', 'tweets', 'screen_name', false);
var store = db.openObjectStore('tweets');
var objKey = store.put({id: 12345667, text: 'Hello World', screen_name: "Joe"});
var index = db.openIndex('ByScreenname');
var matching = index.get('Joe');
if (matching) {
  report(matching.id, matching.screen_name, matching.text);
}
Indexed Database
  • ✔ Lightweight
  • ✔ Indexed → Fast Searches
  • ✔ Transactions
  • ✔ Async and Sync
  • ✔ Browser support is promising
  • ✘ New, evolving
File Storage
document.getElementById("images").onchange = function(ev) {
  for (var i=0; i<this.files.length; i++) {
    (function(file) {
      var fileReader = new FileReader();
      fileReader.onloadend = function() {
        var img = document.createElement("img");  
        img.src = fileReader.result;
        document.body.appendChild(img);
      };
      fileReader.readAsDataURL(file);
    })(this.files[i]);
  }
}

<input type="file" id="images" multiple></p>
File
  • ✔ Binary data
  • ✔ Bridge to Underlying File System
  • ✔ Large content
  • ✔ Async and Sync
  • ✘ Very early
  • ✘ No locking/transactions
  • ✘ Mostly based on "file" control, for now
Offline storage: General issues
  • Size Limits
  • Security
  • Running Smoothly

Offline, And On

Offline:

  • Works when not connected

And On:

  • Fast
  • But wait, more ...
Store locally
Delay the signup...at all costs
Lazy Registration
Host-Proof Hosting
No Server ...
Means No-Hassle Hacking :)

Image Credits

http://www.flickr.com/photos/anirudhkoul/2632880868/sizes/l/in/photostream/
http://www.flickr.com/photos/hendry/3000417490/sizes/l/in/photostream/
http://www.flickr.com/photos/pmiaki/3759228220/sizes/l/in/photostream/
http://www.flickr.com/photos/odalaigh/2625502285/sizes/l/in/photostream/
http://www.baixaki.com.br/download/mugtug-darkroom.htm
http://www.flickr.com/photos/gmacorig/1809288965/sizes/l/in/photostream/
http://www.flickr.com/photos/plutor/1818329845/sizes/l/in/photostream/
http://www.flickr.com/photos/plutor/1818329845/sizes/l/in/photostream/
http://www.flickr.com/photos/96814934@N00/3285550219/sizes/m/in/photostream/
http://www.flickr.com/photos/37184970@N00/5017980645/sizes/l/in/photostream/
http://www.flickr.com/photos/gmacorig/1809288965/sizes/l/in/photostream/
http://www.flickr.com/photos/esti/147733640/sizes/l/in/photostream/
http://www.flickr.com/photos/37184970@N00/4987958271/sizes/o/in/photostream/
http://www.flickr.com/photos/37184970@N00/5018608514/sizes/l/in/photostream/
http://www.flickr.com/photos/eyesplash/4332397307/sizes/l/in/photostream/