offline strategies for html5 web applications - pfcongres2012
TRANSCRIPT
Offline strategies for HTML5 web applicationsStephan Hochdörfer, bitExpert AG
Offline strategies for HTML5 web applications
About me
Stephan Hochdörfer, bitExpert AG
Department Manager Research Labs
enjoying PHP since 1999
@shochdoerfer
Offline strategies for HTML5 web applications
[...] we take the next step, announcing 2014 as the target for
Recommendation.Jeff Jaffe, Chief Executive Officer, World Wide Web Consortium
What does „offline“ mean?
Offline strategies for HTML5 web applications
What does „offline“ mean?
Offline strategies for HTML5 web applications
Application Cache vs. Offline Storage
<! clock.html ><!DOCTYPE HTML><html> <head> <title>Clock</title> <script src="clock.js"></script> <link rel="stylesheet" href="clock.css"> </head> <body> <p>The time is: <output id="clock"></output></p> </body></html>
/* clock.css */output { font: 2em sansserif; }
/* clock.js */setTimeout(function () { document.getElementById('clock').value = new Date();}, 1000);
Application Cache for static resources
Offline strategies for HTML5 web applications
Application Cache for static resources
Offline strategies for HTML5 web applications
CACHE MANIFEST# 20120916clock.htmlclock.cssclock.js
cache.manifest - must be served using the text/cache-manifest MIME type.
<! clock.html ><!DOCTYPE HTML><html manifest="cache.manifest"> <head> <title>Clock</title> <script src="clock.js"></script> <link rel="stylesheet" href="clock.css"> </head> <body> <p>The time is: <output id="clock"></output></p> </body></html>
Application Cache for static resources
Offline strategies for HTML5 web applications
CACHE MANIFEST# 20120916
NETWORK:data.php
CACHE:/main/home/main/app.js/settings/home/settings/app.jshttp://myhost/logo.pnghttp://myhost/check.pnghttp://myhost/cross.png
Application Cache for static resources
Offline strategies for HTML5 web applications
CACHE MANIFEST# 20120916
FALLBACK:/ /offline.html
NETWORK:*
Application Cache for static resources
Offline strategies for HTML5 web applications
Scripting the Application Cache
Offline strategies for HTML5 web applications
// events fired by window.applicationCachewindow.applicationCache.onchecking = function(e) {log("Checking for updates");}window.applicationCache.onnoupdate = function(e) {log("No updates");}window.applicationCache.onupdateready = function(e) {log("Update ready");}window.applicationCache.onobsolete = function(e) {log("Obsolete");}window.applicationCache.ondownloading = function(e) {log("Downloading");}window.applicationCache.oncached = function(e) {log("Cached");}window.applicationCache.onerror = function(e) {log("Error");}
// Log each filewindow.applicationCache.onprogress = function(e) { log("Progress: downloaded file " + counter); counter++;};
Scripting the Application Cache
Offline strategies for HTML5 web applications
// Check if a new cache is available on page load.window.addEventListener('load', function(e) { window.applicationCache.addEventListener('updateready', function(e) {
if(window.applicationCache.status == window.applicationCache.UPDATEREADY) { // Browser downloaded a new app cache. // Swap it in and reload the page window.applicationCache.swapCache(); if (confirm('New version is available. Load it?)) { window.location.reload(); } } else { // Manifest didn't changed. } }, false);
}, false);
Application Cache – Some gotchas!
Offline strategies for HTML5 web applications
Application Cache – Some gotchas!
Offline strategies for HTML5 web applications
1. Files are always(!) served from the application cache.
Application Cache – Some gotchas!
Offline strategies for HTML5 web applications
2. The application cache only updates if the content of the manifest itself
has changed!
Application Cache – Some gotchas!
Offline strategies for HTML5 web applications
3. If any of the files listed in the CACHE section can't be retrieved, the
entire cache will be disregarded.
Application Cache – Some gotchas!
Offline strategies for HTML5 web applications
4. If the manifest file itself can't be retrieved, the cache will ignored!
Application Cache – Some gotchas!
Offline strategies for HTML5 web applications
5. Non-cached resources will not load on a cached page!
Application Cache – Some gotchas!
Offline strategies for HTML5 web applications
6. The page needs to be reloaded, otherwise the new resources do not
show up!
Application Cache – Some gotchas!
Offline strategies for HTML5 web applications
7. To avoid the risk of caching manifest files set expires headers!
The Data URI scheme
Offline strategies for HTML5 web applications
<!DOCTYPE HTML><html> <head> <title>The Data URI scheme</title> <style type="text/css"> ul.checklist li { marginleft: 20px; background: white url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==') norepeat scroll left top;} </style> </head> <body> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot"> </body></html>
The Data URI scheme
Offline strategies for HTML5 web applications
Storing dynamic data locally (in HTML5)
Offline strategies for HTML5 web applications
Storing dynamic data locally (in HTML5)
Offline strategies for HTML5 web applications
Web Storage, Web SQL Database, IndexedDB, File API
Web Storage
Offline strategies for HTML5 web applications
Web Storage
Offline strategies for HTML5 web applications
Very convenient form of offline storage: simple key-value store
Web Storage: 2 different types
Offline strategies for HTML5 web applications
localStorage vs. sessionStorage
var myVar = 123;var myObj = {name: "Stephan"};
// write scalar value to localStoragelocalStorage['myVar'] = myVar;
// read scalar value from localStoragemyVar = localStorage['myVar'];
// write object to localStoragelocalStorage['myObj'] = JSON.stringify(myObj);
// read object from localStoragemyObj = JSON.parse(localStorage['myObj']);
Web Storage: localStorage example
Offline strategies for HTML5 web applications
var myVar = 123;var myObj = {name: "Stephan"};
// write scalar value to sessionStoragesessionStorage['myVar'] = myVar;
// read scalar value from sessionStoragemyVar = sessionStorage['myVar'];
// write object to sessionStoragesessionStorage['myObj'] = JSON.stringify(myObj);
// read object from sessionStoragemyObj = JSON.parse(sessionStorage['myObj']);
Web Storage: sessionStorage example
Offline strategies for HTML5 web applications
function supports_local_storage() { try { return 'localStorage' in window && window['localStorage'] !== null; } catch(e){ return false; }}
Web Storage: Does my browser support it?
Offline strategies for HTML5 web applications
Web Storage: Pro
Offline strategies for HTML5 web applications
Most compatible format up to now.
Web Storage: Con
Offline strategies for HTML5 web applications
The data is not structured.
Web Storage: Con
Offline strategies for HTML5 web applications
No transaction support!
Web SQL Database
Offline strategies for HTML5 web applications
Web SQL Database
Offline strategies for HTML5 web applications
An offline SQL database based on SQLite, an general-purpose SQL engine.
Web SQL Database
Offline strategies for HTML5 web applications
function prepareDatabase(ready, error) { return openDatabase('documents', '1.0', 'Offline document storage', 5*1024*1024, function (db) { db.changeVersion('', '1.0', function (t) { t.executeSql('CREATE TABLE docids (id, name)'); }, error); });}
function showDocCount(db, span) { db.readTransaction(function (t) { t.executeSql('SELECT COUNT(*) AS c FROM docids', [], function (t, r) { span.textContent = r.rows[0].c; }, function (t, e) { // couldn't read database span.textContent = '(unknown: ' + e.message + ')'; }); });}
Web SQL Database: Pro
Offline strategies for HTML5 web applications
It`s a SQL database within the browser!
Web SQL Database: Con
Offline strategies for HTML5 web applications
It`s a SQL database within the browser!
Web SQL Database: Con
Offline strategies for HTML5 web applications
SQLite is slooooow!
Web SQL Database: Con
Offline strategies for HTML5 web applications
The specification is no longer part of HTML5!
IndexedDB
Offline strategies for HTML5 web applications
IndexedDB
Offline strategies for HTML5 web applications
A nice compromise between Web Storage and Web SQL Database giving
you the best of both worlds.
Web SQL Database vs. IndexedDB
Offline strategies for HTML5 web applications
Category Web SQL IndexedDB
Location Tables contain columns and rows
objectStore contains Javascript objects and keys
Query Mechanism
SQL Cursor APIs, Key Range APIs, and Application Code
Transaction Lock can happen on databases, tables, or rows on READ_WRITE transactions
Lock can happen on database VERSION_CHANGE transaction, on an objectStore READ_ONLY and READ_WRITE transactions.
Transaction Commits
Transaction creation is explicit. Default is to rollback unless we call commit.
Transaction creation is explicit. Default is to commit unless we call abort or there is an error that is not caught.
indexedDB.open = function() { var request = indexedDB.open("todos"); request.onsuccess = function(e) { var v = "2.0 beta"; todoDB.indexedDB.db = e.target.result; var db = todoDB.indexedDB.db; if (v!= db.version) { var setVrequest = db.setVersion(v); setVrequest.onfailure = todoDB.indexedDB.onerror; setVrequest.onsuccess = function(e) { if (db.objectStoreNames.contains("todo")) { db.deleteObjectStore("todo"); } var store = db.createObjectStore("todo", {keyPath: "timeStamp"}); todoDB.indexedDB.getAllTodoItems(); }; } else { todoDB.indexedDB.getAllTodoItems(); } }; request.onfailure = todoDB.indexedDB.onerror;};
IndexedDB – Creating an ObjectStore
Offline strategies for HTML5 web applications
IndexedDB – Adding data to ObjectStore
Offline strategies for HTML5 web applications
indexedDB.addTodo = function() { var db = todoDB.indexedDB.db; var trans = db.transaction(['todo'], IDBTransaction.READ_WRITE); var store = trans.objectStore('todo');
var data = { "text": todoText, "timeStamp": new Date().getTime() };
var request = store.put(data); request.onsuccess = function(e) { todoDB.indexedDB.getAllTodoItems(); }; request.onerror = function(e) { console.log("Failed adding items due to: ", e); };};
IndexedDB – Retrieving data
Offline strategies for HTML5 web applications
function show() { var request = window.indexedDB.open("todos"); request.onsuccess = function(event) { var db = todoDB.indexedDB.db; var trans = db.transaction(["todo"], IDBTransaction.READ_ONLY); var request = trans.objectStore("todo").openCursor(); var ul = document.createElement("ul");
request.onsuccess = function(event) { var cursor = request.result || event.result; // If cursor is null, enumeration completed if(!cursor) { document.getElementById("todos").appendChild(ul); return; }
var li = document.createElement("li"); li.textContent = cursor.value.text; ul.appendChild(li); cursor.continue(); } }}
indexedDB.deleteTodo = function(id, text) { var db = todoDB.indexedDB.db; var trans = db.transaction(["todo"], IDBTransaction.READ_WRITE); var store = trans.objectStore("todo");
var request = store.delete(id); request.onsuccess = function(e) { todoDB.indexedDB.getAllTodoItems(); }; request.onerror = function(e) { console.log("Error Adding: ", e); };};
IndexedDB – Deleting data
Offline strategies for HTML5 web applications
File API
Offline strategies for HTML5 web applications
File API
Offline strategies for HTML5 web applications
FileReader API and FileWriter API
function onInitFs(fs) { console.log('Opened file system: ' + fs.name);}
function errorHandler(e) { console.log('Error: ' + e.code);}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);
File API – Requesting access
Offline strategies for HTML5 web applications
window.webkitStorageInfo.requestQuota( PERSISTENT, 5*1024*1024 /*5MB*/, function(grantedBytes) { window.requestFileSystem(PERSISTENT, grantedBytes, onInitFs, errorHandler); }, function(e) { console.log('Error', e);});
File API – Requesting quota
Offline strategies for HTML5 web applications
Offline strategies for HTML5 web applications
function onInitFs(fs) { fs.root.getFile('log.txt', {create: true, exclusive: true}, function(fileEntry) { // fileEntry.name == 'log.txt' // fileEntry.fullPath == '/log.txt' }, errorHandler);}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);
File API – Creating a file
Offline strategies for HTML5 web applications
function onInitFs(fs) { fs.root.getFile('log.txt', {}, function(fileEntry) { fileEntry.file(function(file) { var reader = new FileReader();
reader.onloadend = function(e) { var txtArea = document.createElement('textarea'); txtArea.value = this.result; document.body.appendChild(txtArea); }; reader.readAsText(file); }, errorHandler); }, errorHandler);}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);
File API – Reading a file
Offline strategies for HTML5 web applications
function onInitFs(fs) { fs.root.getFile('log.txt', {create: true}, function(fileEntry) { fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(e) { console.log('Write completed.'); }; fileWriter.onerror = function(e) { console.log('Write failed: ' + e.toString()); };
var bb = new BlobBuilder(); bb.append('Lorem Ipsum'); fileWriter.write(bb.getBlob('text/plain')); }, errorHandler); }, errorHandler);}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);
File API – Writing to a file
Offline strategies for HTML5 web applications
function onInitFs(fs) { fs.root.getFile('log.txt', {create: false}, function(fileEntry) { fileEntry.createWriter(function(fileWriter) {
fileWriter.seek(fileWriter.length);
var bb = new BlobBuilder(); bb.append('Hello World'); fileWriter.write(bb.getBlob('text/plain')); }, errorHandler); }, errorHandler);}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);
File API – Appending data to a file
Offline strategies for HTML5 web applications
function onInitFs(fs) { fs.root.getFile('log.txt', {create: false}, function(fileEntry) { fileEntry.remove(function() { console.log('File removed.'); }, errorHandler); }, errorHandler);}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);
File API – Deleting a file
Offline strategies for HTML5 web applications
File API – Creating directories
Offline strategies for HTML5 web applications
function onInitFs(fs) { fs.root.getDirectory('MyFolder', {create: true}, function(dirEntry) { // do stuff... }, errorHandler);}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);
File API – Browser support?
Offline strategies for HTML5 web applications
Up to now: Chrome only
File API – Browser support?
Offline strategies for HTML5 web applications
But: idb.filesystem.js
Am I online?
Offline strategies for HTML5 web applications
document.body.addEventListener("online", function () { // browser is online!}
document.body.addEventListener("offline", function () { // browser is not online!}
Am I online?
Offline strategies for HTML5 web applications
$.ajax({ dataType: 'json', url: 'http://myappurl.com/ping', success: function(data){ // ping worked }, error: function() { // ping failed > Server not reachable }});
Am I online? Another approach...
Offline strategies for HTML5 web applications
Thank you!
http://joind.in/7073