Offline & You

Josh Matthews, Mozilla developer

What does being offline mean?

Gee, that sounds pretty dull.

Offline storage

LocalStorage/SessionStorage

IndexedDB

Much more complex than Web Storage, being based around asynchronous transactions.

Most API functions returns a request
var request = window.indexedDB.open("myDatabase", /* optional version number */ 1);
request.onsuccesss = function(event) { /* db handle in request.result */ };
request.onerror = function(event) { /* specific error in event.target.errorCode */ };
Requires structured data descriptions
// Create an objectStore to hold information about our customers. We're
// going to use "ssn" as our key path because it's guaranteed to be
// unique.
var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });
 
// Create an index to search customers by name. We may have duplicates
// so we can't use a unique index.
objectStore.createIndex("name", "name", { unique: false });
 
// Create an index to search customers by email. We want to ensure that
// no two customers have the same email, so use a unique index.
objectStore.createIndex("email", "email", { unique: true });

IndexedDB

Transactions
var transaction = db.transaction(["customers"], "readwrite");
// transaction is a request; add your onsuccess and onerror handlers

var objectStore = transaction.objectStore("customers");
objectStore.add({name: "Jane", email: "jane@jane.tld", ssn: "444-33-4444"});

// or

objectStore.delete({"444-33-4444"});

// or

var request = objectStore.get({"444-334444"});
// set up your onsuccess and onerror handlers; the result is request.result.{field name}

IndexedDB

Still to come - iterating all or some values in a store, upgrading object stores, using indexes, handling different DB versions in separate tabs...

Unfortunately, most browsers ship different and slightly incompatible implementations due to spec changes

Given that, I recommend letting other people do the hard work for you:

IDBWrapper is one library to try if IndexedDB appears intimidating

Dealing with remote resources

Consider starting up a mobile game on the subway.

Three separate concerns:

Application Cache Manifest (Appcache)

index.html

<html manifest="manifest.cache">

manifest.cache

CACHE MANIFEST
CACHE:
index.html
highscores.html
style.css
code.js

NETWORK:
highscores.php
/cgi-bin/*

FALLBACK:
highscores.php highscores.html

The CACHE section

function onUpdateReady() {
  // Ensure the browser uses the latest version of the code
  applicationCache.swapCache();
  // Reload the application
  location.reload();
}

applicationCache.addEventListener('updateready', onUpdateReady);
if(applicationCache.status === applicationCache.UPDATEREADY) {
  onUpdateReady();
}

The NETWORK section

The FALLBACK section

Example: attempt to fetch dynamic highscores for a game; if that fails, fall back to a static page with default scores.

Store the player's scores locally and update the list accordingly.

Detecting offline-ness

Short answer: attempt a network request.

Two main choices:

Either way you need to handle failure of an actual remote request that is supposed to do something.

Useful tip

Bootstrap the detection process by observing the appcache's error event on page load.

window.applicationCache.addEventListener("error", function(e) {
  alert("Error fetching manifest: a good chance we are offline");
});

Tips for pushing updates

Expect and account for failures.

Consider showing updated data locally.

Buffer updates, push them as a group when network available.

Offline Geolocation

navigator.geolocation.getCurrentPosition/watchPosition allow retrieving cached data via maxAge.

Once you obtain a valid position, consider how long an app can be useful while using outdated data.

Putting it all together

Put your static resources in the appcache.

Fetch dynamic data when possible, and keep it in offline storage if it will be useful later.

Fall back to most recent static data when dynamic data is impossible.

Store updates until they are transmitted - even between sessions.

Handle failure gracefully!

Now go and build!


Josh Matthews - www.joshmatthews.net

josh@joshmatthews.net - @lastontheboat

/

#