Stephan Hochdörfer // 04.09.2015
<!DOCTYPE html> <html lang="en">
<!DOCTYPE html> <html lang="en" manifest="cache.manifest">
CACHE MANIFEST # 2015-09-04 js/app.js css/app.css favicon.ico http://someotherdomain.com/image.png
CACHE MANIFEST # 2015-09-04 NETWORK: data.php CACHE: /main/home /main/app.js /settings/home /settings/app.js http://myhost/logo.png http://myhost/check.png http://myhost/cross.png
CACHE MANIFEST # 2015-09-04 FALLBACK: / /offline.html NETWORK: *
// Check if a new cache version is available window.addEventListener('load', function(e) { window.applicationCache.addEventListener('updateready', function(e) { if(window.applicationCache.status == window.applicationCache.UPDATEREADY) { window.applicationCache.swapCache(); if (confirm('New version is available. Load it?')) { window.location.reload(); } } }, false); }, false);
Dateien werden immer(!)
vom lokalen Cache ausgeliefert.
Der lokale Cache wird nur dann aktualisiert
wenn sich die manifest Datei geändert hat.
Nicht ladbare Dateien aus der CACHE Sektion
führen dazu dass der Cache invalide ist.
Kann die manifest Datei nicht geladen werden,
erfolgt kein Caching!
Nicht gecachte Ressourcen werden auf
einer gecachten Seite nicht angezeigt.
Nach Aktualisierung des Caches muss
die Seite neu geladen werden!
Mit expires Header arbeiten um das
Cachen des manifests zu verhinden!
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/worker.js').then(function(reg) { // Registration was successful }).catch(function(err) { // Registration failed }); }
var CACHE_NAME = 'my-site-cache-v1'; var urlsToCache = [ '/', '/styles/main.css', '/script/main.js' ]; self.addEventListener('install', function(event) { event.waitUntil( caches.open(CACHE_NAME) .then(function(cache) { return cache.addAll(urlsToCache); }) ); });
self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { if (response) { return response; } return fetch(event.request); } ) ); });
Komfortable Art Daten offline zu
speichern: Key/Value Speicher
localStorage vs. sessionStorage
function add(item) { try { // for a new item set id if((typeof item.id === "undefined") || (null == item.id) || ("" == item.id)) { item.id = get_lastIndex() + 1; } // store object as string localStorage.setItem(item.id, JSON.stringify(item) ); // update the index set_lastIndex(item.id); } catch(ex) { console.log(ex); } }
function modify(item) { try { // store object as string localStorage.setItem(item.id, JSON.stringify(item) ); } catch(ex) { console.log(ex); } }
function remove (id) { try { localStorage.removeItem(id); } catch(ex) { console.log(ex); } }
function read() { try { var lastIdx = get_lastIndex(); for(var i = 1; i <= lastIdx; i++) { if(null !== localStorage.getItem(i)) { // parse and render item var item = JSON.parse( localStorage.getItem(i) ); } } } catch(ex) { console.log(ex); } }
Eine lokale SQL Datenbank auf SQLite Basis.
var onError = function(tx, ex) { alert("Error: " + ex.message); }; var onSuccess = function(tx, results) { var len = results.rows.length; for(var i = 0; i < len; i++) { // render found todo item render(results.rows.item(i)); } };
// initalize the database connection var db = openDatabase('todo', '1.0', 'Todo Database', 5 * 1024 * 1024 ); db.transaction(function (tx) { tx.executeSql( 'CREATE TABLE IF NOT EXISTS todo '+ '(id INTEGER PRIMARY KEY ASC, todo TEXT)', [], onSuccess, onError ); });
function m1(t){ t.executeSql("create table tbl1...") } function m2(t){ t.executeSql("alter table tbl1...") } function m3(t){ t.executeSql("alter table tbl1...") } if(db.version == "") { db.changeVersion("", "1", m1, null, function() { db.changeVersion("1", "2", m2, null, function() { db.changeVersion("2", "3", m3); }); }); } if(db.version == "1") { db.changeVersion("1", "2", m2, null, function() { db.changeVersion("2", "3", m3); }); } if(db.version == "2") { db.changeVersion("2", "3", m3); }
function add(item) { db.transaction(function(tx) { tx.executeSql( 'INSERT INTO todo (todo) VALUES (?)', [ item.todo ], onSuccess, onError ); }); }
function modify(item) { db.transaction(function(tx) { tx.executeSql( 'UPDATE todo SET todo = ? WHERE id = ?', [ item.todo item.id ], onSuccess, onError ); }); }
function remove(id) { db.transaction(function (tx) { tx.executeSql( 'DELETE FROM todo WHERE id = ?', [ id ], onSuccess, onError ); }); }
function read() { db.transaction(function (tx) { tx.executeSql( 'SELECT * FROM todo', [], onSuccess, onError ); }); }
Kompromiss aus Web Storage
und Web SQL Database.
// different browsers, different naming conventions var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB; var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction; var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
var db = null; var request = indexedDB.open("todo"); request.onfailure = onError; request.onsuccess = function(e) { db = request.result; var v = "1.0"; if(v != db.version) { var verRequest = db.setVersion(v); verRequest.onfailure = onError; verRequest.onsuccess = function(e) { var store = db.createObjectStore("todo", { keyPath: "id", autoIncrement: true }); e.target.transaction.oncomplete = function() {}; }; } };
function add(item) { try { var trans = db.transaction(["todo"], IDBTransaction.READ_WRITE); var store = trans.objectStore("todo"); var request = store.put({ "todo": item.todo, }); } catch(ex) { onError(ex); } }
function modify(item) { try { var trans = db.transaction(["todo"], IDBTransaction.READ_WRITE); var store = trans.objectStore("todo"); var request = store.put(item); } catch(ex) { onError(ex); } }
function remove(id) { try { var trans = db.transaction(["todo"], IDBTransaction.READ_WRITE); var store = trans.objectStore("todo"); var request = store.delete(id); } catch(ex) { onError(ex); } }
function read () { try { var trans = db.transaction(["todo"], IDBTransaction.READ); var store = trans.objectStore("todo"); var keyRange = IDBKeyRange.lowerBound(0); var cursorRequest = store.openCursor(keyRange); cursorRequest.onsuccess = function(e) { var result = e.target.result; if(!!result == false) { return; } // @TODO: render result.value result.continue(); }; } catch(ex) { onError(ex); } }
try { var index = db.openIndex('todo'); var item = index.get(1337); } catch(ex) { onError(ex); }
try { // create non-unique index db.createIndex("Created", "createdDate", {"unique": false}); // create unique index db.createIndex("OtherKey", "otherField", {"unique": true}); // create multi-column index (not working in IE10!) db.createIndex("MultiIndex", ["field1", "field2"]); } catch(ex) { onError(ex); }
var onError = function(e) { var msg = ''; switch(e.code) { case FileError.QUOTA_EXCEEDED_ERR: msg = 'QUOTA_EXCEEDED_ERR'; break; case FileError.NOT_FOUND_ERR: msg = 'NOT_FOUND_ERR'; break; case FileError.SECURITY_ERR: msg = 'SECURITY_ERR'; break; case FileError.INVALID_MODIFICATION_ERR: msg = 'INVALID_MODIFICATION_ERR'; break; case FileError.INVALID_STATE_ERR: msg = 'INVALID_STATE_ERR'; break; default: msg = 'Unknown Error'; break; }; alert("Error: " + msg); };
// File system has been prefixed as of Google Chrome 12 window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem; window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder; var size = 5 * 1024*1024; // 5MB
// request quota for persistent store window.webkitStorageInfo.requestQuota( PERSISTENT, size, function(grantedBytes) { window.requestFileSystem( PERSISTENT, grantedBytes, function(fs) { // @TODO: access filesystem } } } }
function add(item) { window.webkitStorageInfo.requestQuota( PERSISTENT, size, function(grantedBytes) { window.requestFileSystem( PERSISTENT, grantedBytes, function(fs) { writeToFile(fs, item); }, onError ); }, function(e) { onError(e); } ); }
function writeToFile(fs, item) { fs.root.getFile( 'todo.txt', { create: true }, function(fileEntry) { fileEntry.createWriter( function(fileWriter) { var blob = new Blob([JSON.stringify(item)+"\n"]); fileWriter.seek(fileWriter.length); fileWriter.write(blob); }, onError ); }, onError ); }
function read() { window.webkitStorageInfo.requestQuota( PERSISTENT, size, function(grantedBytes) { window.requestFileSystem( PERSISTENT, grantedBytes, function(fs){ readFromFile(fs); }, onError ); }, function(e) { onError(e); } ); }
function readFromFile(fs) { fs.root.getFile( 'todo.txt', { create: true }, function(fileEntry) { fileEntry.file(function(file){ var reader = new FileReader(); reader.onloadend = function(e) { if (evt.target.readyState == FileReader.DONE) { // process this.result } }; reader.readAsText(file); }); }, onError ); }
Web Storage | Web SQL DB | IndexedDB | File API | |
IE | 8.0 | 10.0 | 10.0 | - |
Firefox | 11.0 | 11.0 | 11.0 | 19.0 |
Chrome | 18.0 | 18.0 | 18.0 | 18 |
Safari | 5.1 | 5.1 | - | - |
iOS | 3.2 | 3.2 | - | - |
Android | 2.1 | 2.1 | - | - |
Web Storage | Web SQL DB | IndexedDB | File API | |
IE | 10 MB | 500 MB | 500 MB | |
Firefox | 10 MB | 50 MB | 50 MB | |
Chrome | 5 MB | ∞ | ∞ | ∞ |
Safari | 5 MB | 5 MB | 5 MB | |
iOS | 5 MB | 5 MB | 5 MB | |
Android | 5 MB | ? | ? |
PouchDB, the JavaScript Database that syncs!
var db = new PouchDB('todo'); db.put({ _id: 1, todo: 'Get some work done...', }); db.replicate.to('http://myapp.com/mydb');
Vielen Dank! Fragen?
Feedback zum Vortrag:
https://joind.in/15097