Offline Mode
Web Applications for Offline Use
@pleckey | http://pleckey.me
Who is this guy?
Patrick Leckey
Director of Engineering
In-Touch Insight Systems Inc.
http://www.intouchinsight.com
Online is easy
Offline is ... easy?
But what if ...
... you're not guaranteed to have connectivity the whole way ...
What we have now ...
LocalStorage
window.localStorage
ApplicationCache
window.applicationCache
Chrome: 4+, Firefox: 3.5+, Safari: 4+
Mobile Safari: 3.2+, Android Browser: 2.1+
IE: 10+
LocalStorage
simplestraightforward
rather limited
ApplicationCache
complexconfusing
powerful
LocalStorage
... it's basically a shelf ...
Put stuff on the shelf
Take stuff off the shelf
Can only hold so much stuff
LocalStorage
Similar to Cookies
... but not transmitted on each request
Send what you want, when you want!
LocalStorage
- Key / Value pairs
- Limited storage size
Same Origin Policy!
http://pleckey.me != https://www.pleckey.me
LocalStorage
- 5 MB limit
- As JavaScript strings ...
1.2345678
4 byte float? 9 bytes of characters?
Nope!
18-byte UTF-16 string
LocalStorage
window.localStorage.getItem( 'foo' ); // null
window.localStorage.setItem( 'foo', 'bar' );
window.localStorage.getItem( 'foo' ); // "bar"
window.localStorage.length; // 1
JSON.stringify( window.localStorage ); // {"foo": "bar"}
window.localStorage.removeItem( 'foo' ); // does nothing if key doesn't exist
window.localStorage.clear(); // remove ALL items
LocalStorage
What happens when the shelf is full?
try {
window.localStorage.setItem( 'foo', really_big_thing );
} catch ( e /* DOMException */ ) {
if ( e.name == 'QuotaExceededError' )
// Chrome, Safari, IE
else if ( e.name == 'NS_ERROR_DOM_QUOTA_REACHED' )
// Firefox
}
LocalStorage
Good Ideas
application state
user information
user information
Bad Ideas
base64-encoded images
postal code lookup database
postal code lookup database
ApplicationCache
... is basically a ... uh ... cache ...
Pre-cache resources
Access resources offline
Fallback to alternates for dynamic resources
ApplicationCache
- No storage limit
- Event-driven API
Cache is based on manifest URL
ApplicationCache
<html manifest="/cache.manifest">
mime type must be text/cache-manifest
cache.manifest
CACHE
NETWORK
FALLBACK
NETWORK
FALLBACK
cache.manifest
CACHE
CACHE MANIFEST
# Version: 8cf54be2
CACHE:
/favicon.png
/logo.png
/site/page2.html
explicitly cached resources
cache.manifest
NETWORK
CACHE MANIFEST # Version: 8cf54be2 CACHE: /favicon.png ... NETWORK:
*
resources that require the user to be online
usually just "*"
cache.manifest
FALLBACK
CACHE MANIFEST
# Version: 8cf54be2
CACHE:
/favicon.png
/static.html
NETWORK:
*
FALLBACK:
/dynamic.php /static.html
resource to load if requested resource not available offline
ApplicationCache
cached items are always served from the application cache
the application cache will not update unless the cache manifest file content changes
ApplicationCache
CACHE MANIFEST
# Version: 8cf54be2
CACHE:
/script.js
NETWORK:
*
text content has to be changed
Pretty Simple, right?
... and you thought it'd be that easy ...
Oops #1
Non-cached resources don't exist.
Even when you're online.
NETWORK:
*
Oops #2
The application cache works with the browser cache.
Sort of.
Cache-Control: max-age=9999999999
Oops #3
Caching the cache manifest.
It'll never update.
Cache-Control: no-cache, no-store
Clearing the ApplicationCache
HTTP/1.0 410 Gone
ApplicationCache Events
window.applicationCache.addEventListener( ... );
/** * 'checking' - browser is checking for an update (always first) * * 'cached' - fired after first download of a new cache manifest * * 'downloading' - new / updated resources found, browser is fetching * * 'error' - manifest returned 404 or a download failed * * 'noupdate' - cache manifest has not changed * * 'obsolete' - manifest returned 410, cache deleted * * 'progress' - X of Y manifest resources downloaded * * 'updateready' - all updates downloaded */
ApplicationCache API
window.applicationCache.addEventListener( 'updateready', function( e ) {
alert( 'New version downloaded. Application will now reload.' );
window.location.reload();
} );
window.applicationCache.update();
ApplicationCache API
window.applicationCache.addEventListener( 'updateready', function( e ) {
alert( 'New version downloaded. Application will now reload.' );
window.applicationCache.swapCache();
} );
window.applicationCache.update();
iframe is your friend
<!-- iframe_js.html -->
<html>
<script type="application/javascript">
var awesome_data = { con: "foo", bar: "baz" };
if ( window.parent != window ) window.parent.awesome_data = awesome_data;</script>
</html>
store large lookup data in iframes
iframe is your friend
<!-- index.html -->
<html manifest="/cache.manifest">
<iframe src="iframe_js.html" width="0" height="0" border ="0"/>
</html>
CACHE MANIFEST
# Version: 1
CACHE:
/iframe_js.html
NETWORK:
*
include lookup data in cache manifest
load via iframe (same origin)
iframe is your friend
// index.html console
> window.awesome_data
Object {con: "foo", bar: "baz"}
var appCache = window.applicationCache;
if ( appCache.status != appCache.status.CACHED ) {
// not cached yet, do an AJAX lookup
} else {
return window.awesome_data.con; // "foo"
}
Single Page Applications
pre-cache static resources (speed!)
Native(ish) Web App
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="mobile-web-app-capable" content="yes"/>
runs full screen
built-in software updates
queue data for submission later
What Else Can I Do With This?
Come work for us!
Software Developer
User Experience
Data Scientist
Thank you!
Questions?
@pleckey | http://pleckey.com
Offline mode
By Patrick Leckey
Offline mode
- 2,387