Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Offline web apps

Offline web apps

This talk will cover 3 important parts of offline web apps - service workers, app cache and client-side storage. Service workers are cool new event-driven workers that enables our web apps to fully work offline, including intercepting and modifying requests, handle caching etc. Unfortunately it still doesn't work in all browsers, so we still need App cache in some cases - older and not so great solution for offline caching but it works in all major browsers. For fully-functional web apps we need to have some kind of a client-side storage, last part of the talk will review Indexed DB, Web SQL and of course localStorage.

Slobodan Stojanović

March 12, 2016
Tweet

More Decks by Slobodan Stojanović

Other Decks in Programming

Transcript

  1. Slobodan Stojanovic Slobodan Stojanovic I am I am github.com/stojanovic github.com/stojanovic

    twitter.com/slobodan_ twitter.com/slobodan_ slobodan.me slobodan.me
  2. "Web" and "online" are two closely as sociated terms, downright

    synonymous to many people. So why on earth would we talk about "offline" web technolo gies, and what does the term even mea n? http://www.html5rocks.com/en/tutorials/offline/whats-offline/
  3. ... ​Everyone's happy, nothing is broken o r smudged. There

    is infinite wi-fi wi th infinite bandwidth, no batteries r un out, no traffic no delays. ... http://blog.tobiasrevell.com/2013/12/critical-design-design- fiction-lecture.html
  4. What are the problems with What are the problems with

    online only apps? online only apps?
  5. Issues in transport Issues in transport Airlines, high-speed trains, subway...

    Airlines, high-speed trains, subway... (Hyperloop?) (Hyperloop?)
  6. Bad connection Bad connection Far from modem or any other

    reason Far from modem or any other reason
  7. Why do we treat web apps Why do we treat

    web apps differently than native? differently than native?
  8. How to sync the app with How to sync the

    app with the server? the server?
  9. navigator.onLine navigator.onLine is a property that maintains a true/false value

    (true for online, false for offline). This property is updated whenever the user switches into "Offline Mode"
  10. "online" and "offline" events These two events are fired on

    the <body> of each page when the browser switches between online and offline mode. Additionally, the events bubble up from document.body, to document, ending at window.
  11. Benefits Benefits Offline browsing: users can navigate a site even

    when they are offline. Speed: cached resources are local, and therefore load faster. Reduced server load: the browser only downloads resources that have changed from the server.
  12. <html manifest="example.appcache"> ... </html> index.html example.appcache CACHE MANIFEST # v1

    2015/12/26 <- This is just a comment index.html cache.html style.css image1.png # Use from network if available NETWORK: /api # Fallback content FALLBACK: /foo/bar fallback.html
  13. window.applicationCache const appCache = window.applicationCache; switch (appCache.status) { case appCache.UNCACHED:

    // UNCACHED == 0 return 'UNCACHED'; break; case appCache.IDLE: // IDLE == 1 return 'IDLE'; break; case appCache.CHECKING: // CHECKING == 2 return 'CHECKING'; break; case appCache.DOWNLOADING: // DOWNLOADING == 3 return 'DOWNLOADING'; break; case appCache.UPDATEREADY: // UPDATEREADY == 4 return 'UPDATEREADY'; break; case appCache.OBSOLETE: // OBSOLETE == 5 return 'OBSOLETE'; break; default: return 'UKNOWN CACHE STATUS'; break; };
  14. events: // Fired after the first cache of the manifest.

    appCache.addEventListener('cached', handleCacheEvent, false); // Checking for an update. Always the first event fired in the sequence. appCache.addEventListener('checking', handleCacheEvent, false); // An update was found. The browser is fetching resources. appCache.addEventListener('downloading', handleCacheEvent, false); // The manifest returns 404 or 410, the download failed, // or the manifest changed while the download was in progress. appCache.addEventListener('error', handleCacheError, false); // Fired after the first download of the manifest. appCache.addEventListener('noupdate', handleCacheEvent, false); // Fired if the manifest file returns a 404 or 410. // This results in the application cache being deleted. appCache.addEventListener('obsolete', handleCacheEvent, false); // Fired for each resource listed in the manifest as it is being fetched. appCache.addEventListener('progress', handleCacheEvent, false); // Fired when the manifest resources have been newly redownloaded. appCache.addEventListener('updateready', handleCacheEvent, false);
  15. "Application Cache is a Douchebag" http://alistapart.com/article/application-cache-is-a-douchebag​ Files always come from

    the applicationcache, even if you’re online; The application cache only updates if the content of the manifest itself has changed​; Never ever ever far-future cache the manifest; Non-cached resources will not load on a cached page; ...
  16. Deprecated This feature has been removed from the Web standards.

    They recommend using Service Workers instead.
  17. Service workers essentially act as prox y servers that sit

    between web applicat ions, and the browser and network (when available.)
  18. var CACHE_NAME = 'my-site-cache-v1'; var urlsToCache = [ '/', '/styles/main.css',

    '/script/main.js' ]; self.addEventListener('install', function(event) { // Perform install steps event.waitUntil( caches.open(CACHE_NAME) .then(function(cache) { console.log('Opened cache'); return cache.addAll(urlsToCache); }) ); }); Cache resources
  19. self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { // Cache hit

    - return response if (response) { return response; } return fetch(event.request); } ) ); }); Cache requests
  20. this.addEventListener('install', function(event) { event.waitUntil( caches.open('v2').then(function(cache) { return cache.addAll([ '/sw-test/', '/sw-test/index.html',

    '/sw-test/style.css', '/sw-test/app.js', '/sw-test/image-list.js', // … // include other new resources for the new version... ]); }); ); }); Updating service worker
  21. this.addEventListener('activate', function(event) { var cacheWhitelist = ['v2']; event.waitUntil( caches.keys().then(function(keyList) {

    return Promise.all(keyList.map(function(key) { if (cacheWhitelist.indexOf(key) === -1) { return caches.delete(key); } })); }) ); }); Deleting old cache
  22. The localStorage property allows you to access a local Storage

    object. localStorage is similar to sessionStorage. The only difference is that, while data stored inlocalStorage has no expiration time, data stored in sessionStorage gets cleared when the browsing session ends - that is, when the browser is closed.
  23. Deprecated Since November 18, 2010, the W3C announced that Web

    SQL database is a deprecated specification.
  24. IndexedDB is a low-level API for client-side storage of significant

    amounts of structured data, including files/blobs.
  25. It uses indexes to enable high performance searches. It lets

    you store and retrieve objects that are indexed with a key. Any objects supported by the can be stored. structured clone algorithm
  26. Structured clone algorithm Structured clone algorithm The structured clone algorithm

    is a new algorithm for serializing complex JavaScript objects. The algorithm, in essence, walks over all the fields of the original object, duplicating the values of each field into a new object. defined by the HTML5 specification
  27. Structured clones can duplicate*: objects objects objects objects objects ...

    It cannot duplicate: objects objects DOM ... RegExp Blob File ImageData FileList Error Function
  28. Concepts Concepts IndexedDB databases store key-value pairs IndexedDB is built

    on a transactional database model The IndexedDB API is mostly asynchronous IndexedDB uses a lot of requests IndexedDB uses DOM events to notify you when results are available IndexedDB is object-oriented IndexedDB does not use SQL IndexedDB adheres to a same-origin policy
  29. window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; //

    DON'T use "var indexedDB = ..." if you're not in a function. window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"}; window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange; // (Mozilla has never prefixed these objects, so we don't need window.mozIDB*) if (!window.indexedDB) window.alert(`Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.`);
  30. var db; var request = indexedDB.open("MyTestDatabase"); request.onerror = function(event) {

    console.error('Database error', event.target.errorCode); }; request.onsuccess = function(event) { db = event.target.result; }; // This event is only implemented in recent browsers request.onupgradeneeded = function(event) { var db = event.target.result; // ... };
  31. const dbName = "the_name"; var request = indexedDB.open(dbName, 2); request.onerror

    = function(event) { /* Handle errors. */ }; request.onupgradeneeded = function(event) { var db = event.target.result; // 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 here. objectStore.createIndex("name", "name", { unique: false }); // Create an index to search customers by email. objectStore.createIndex("email", "email", { unique: true }); // Use transaction oncomplete to make sure the objectStore creation is // finished before adding data into it. objectStore.transaction.oncomplete = function(event) { // Store values in the newly created objectStore. var customerObjectStore = db.transaction("customers", "readwrite") .objectStore("customers"); for (var i in customerData) { customerObjectStore.add(customerData[i]); } }; };
  32. Offline Recipes for Offline Recipes for Service Workers Service Workers

    https://hacks.mozilla.org/2015/11/offline-service-workers/​
  33. Apps that need to work with Apps that need to

    work with unstable internet connection unstable internet connection Apps for warehouses, factories, and other places with unstable web conditions..
  34. Content based apps Content based apps Where ever you want

    user to be able to access some content that he already saw regardless of the connection
  35. Better (client side) caching Better (client side) caching For better

    user experience, faster apps with less server load
  36. Slobodan Stojanovic Slobodan Stojanovic I am I am github.com/stojanovic github.com/stojanovic

    twitter.com/slobodan_ twitter.com/slobodan_ slobodan.me slobodan.me
  37. slides.com/slobodan/offline- slides.com/slobodan/offline- web-apps web-apps Offline web apps Offline web apps

    handbook [WIP]: handbook [WIP]: github.com/stojanovic/offline github.com/stojanovic/offline -webapps -webapps This presentation: This presentation: