Offline JS
@agup
Can JS apps work offline?
Demo
esri.github.io/offline-editor-js/demo/
Why offline JS?
Loss of connection is common in mobile apps!!
Consumer
Commercial
Government
Why offline JS?
Allow users to keep working, seamlessly
Avoid application crashes or errors
Gracefully fail or degrade
Why offline JS?
Slow or intermittent cellular internet
Slow or intermittent WiFi
Avoid HTTP Timeouts
Why offline JS?
Why offline JS?
You don't have to be remote!
Can lose internet at any time.
Offline JS is caching of:
Data
HTTP requests
HTML/CSS/JS/images
Does browser storage work offline?
Does Geolocation work offline?
Intermittent offline
Full offline
&
Most common.
Offline for a short period of time
Does not require browser restart
Fail gracefully, graceful degradation
Intermittent Offline
Online
Offline
Online
Intermittent Offline
Bad, bad, bad
HTTP Request
Good, good, good
HTTP Request
Fully Offline
Offline for an extended time
Expect full functionality
Requires offline browser restart
Online
Offline
Online
Fully Offline
Restart
Browser
APIs...?
Native JavaScript
localStorage
IndexedDB
Application Cache
Service Workers
3rd party storage libraries
localStorage
Simple to use
Limited to 5 MBs
Store only Strings
Persistent between browser restarts
localStorage
// Window.localStorage
// Set an item -- Must be a String
localStorage.pageNumber = "2";
// Get an item
var pageNumber = localStorage.pageNumber;
// Remove an item
localStorage.removeItem("pageNumber");
IndexedDB
More complex than localStorage
50 - 100MB + (on mobile devices)
Stores Objects, Strings and more
IndexedDB
var transaction = db.transaction(["myObjectStore"], "readwrite");
transaction.oncomplete = function (event) {
dbOnCompleteHandler(event);
};
transaction.onerror = function (event) {
alert("There was a problem writing to the database");
};
var objectStore = transaction.objectStore("myObjectStore");
// Write object to database
objectStore.put(object);
Application Cache
A.K.A. Cache Manifest, AppCache
Stores .html, .js, .css and images
Files available online and offline
Temperamental
Application Cache
Use with localStorage/IndexedDB!
Browser automatically recognizes the local copy
Application Cache
<html manifest="example.appcache">
...
</html>
CACHE MANIFEST
# Time: Thu Mar 26 2015 09:45:14 GMT-0600 (MDT)
# Home Page
http://www.example.com/index.html
http://www.example.com/main.js
http://www.example.com/css/main.css
http://www.example.com/images/header.png
/example.appcache
Application Cache
Typical console log...
Service Workers
Very limited support (Chrome)
Requires HTTPS
Acts as a network proxy
More complex than AppCache
3rd Party Storage
PouchDB, localForage
They wrap localStorage, IndexedDB and/or WebSQL
Require an addt'l library
Offer addt'l features
Detecting offline?
Offline.js (3 kb)
Set HTTP.timeout
Capture HTTP request failure
Caveats:
- 404's and connection issues
- Use Hybrid detection when available
XHR validate online
function validateOnline(callback) {
var req = new XMLHttpRequest();
req.timeout = 15000; //ms
req.open("GET", "http://someurl.com/test.png?" +
(Math.floor(Math.random() * 1000000000)), true);
req.onload = function() {
if( req.status === 200 && req.responseText !== "") {
req = null;
callback(true);
}
else {
req = null;
callback(false);
}
};
req.ontimeout = function() { callback( false ); };
req.onerror = function() { callback(false); };
req.send(null);
}
Offline.js - simple
function buttonClickHandler() {
Offline.check();
// Fail gracefully if offline
if(Offline.state === "down") {
alert("Sorry, app is currently offline");
}
else {
// Do something
}
}
Offline.js - advanced
function submitFormClickHandler() {
Offline.check();
var newAddress = street + "," + city + "," + zip;
// Store changes locally
if(Offline.state === "down") {
localStorage.newAddress = localStorage.newAddress +
"|@|" + newAddress;
}
else {
sendDataToServer( newAddress );
}
}
Offline.on("up", function() {
sendDataToServer( localStorage.newAddress, function() {
localStorage.newAddress = null;
});
});
Caveat Emptor
Very difficult to determine why HTTP requests fail.
What about hybrid?
PhoneGap/Cordova, Titanium, etc
Use the same JS coding patterns!
Cordova check network status:
cordova-plugin-network-information
Check network (Cordova)
function checkConnection() {
var networkState = navigator.connection.type;
var states = {};
states[Connection.UNKNOWN] = 'Unknown connection';
states[Connection.ETHERNET] = 'Ethernet connection';
states[Connection.WIFI] = 'WiFi connection';
states[Connection.CELL_2G] = 'Cell 2G connection';
states[Connection.CELL_3G] = 'Cell 3G connection';
states[Connection.CELL_4G] = 'Cell 4G connection';
states[Connection.CELL] = 'Cell generic connection';
states[Connection.NONE] = 'No network connection';
return states[networkState];
}
var internetStatus = checkConnection();
How permanent is storage?
Browser crash or device restart = okay
User clears browser cache = not good
Full device reset = not good
Best practices
Always:
Listen for offline conditions
Protect all HTTP requests
Set HTTP timeout
Cache resources when feasible
Best practices
Use as little memory as possible!
Upload 14MB zip
Add 1.5MBs to IndexedDB
___________________
Cached 196MB
===============
Andy Gup
agup@esri.com @agup
andygup.net
Bonus slide
How much browser storage?
Offline JS
By Andy G
Offline JS
A short stroll thru the ins and outs of offline JavaScript
- 4,373