Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Progressive What Apps?

Progressive Web Apps are one of the hottest things to come to the web platform in years, but how much of it is just hot air? When can you actually start shipping these things? Decades ago! In a hands on presentation, I'll show how PWAs are truly meant to be progressive - building on an evolution of web technologies nearly as old as the web itself, and still let you ship one of the most performant and cutting edge web apps around.

  • Login to see the comments

  • Be the first to like this

Progressive What Apps?

  1. 1. Progressive Web Apps @PatrickKettner
  2. 2. Progressive What Apps? @PatrickKettner
  3. 3. calm a baby
  4. 4. 2G Ruined My Day45M Ruined My Day
  5. 5. When you don’t have a better idea, buy a novelty domain
  6. 6. https://HushLittleBa.by Baby soothing goodness in <6k
  7. 7. ServiceWorker
  8. 8. let CURRENT_CACHE = { prefetch: 'prefetch-cache-v1' }; self.addEventListener('install', event => { let prefetch = ['/T0t411y-R4D-Sans'] event.waitUntil(caches.open(CURRENT_CACHE['prefetch']) .then(cache => cache.addAll(prefetch.map((url) => new Request(url, { 'mode': 'no-cors' }) )) ) ) })
  9. 9. let CURRENT_CACHE = { prefetch: 'prefetch-cache-v1' }; self.addEventListener('install', event => { let prefetch = ['/T0t411y-R4D-Sans'] event.waitUntil(caches.open(CURRENT_CACHE['prefetch']) .then(cache => cache.addAll(prefetch.map((url) => new Request(url, { 'mode': 'no-cors' }) )) ) ) })
  10. 10. let CURRENT_CACHE = { prefetch: 'prefetch-cache-v1' }; self.addEventListener('install', event => { let prefetch = ['/T0t411y-R4D-Sans'] event.waitUntil(caches.open(CURRENT_CACHE['prefetch']) .then(cache => cache.addAll(prefetch.map((url) => new Request(url, { 'mode': 'no-cors' }) )) ) ) })
  11. 11. let CURRENT_CACHE = { prefetch: 'prefetch-cache-v1' }; self.addEventListener('install', event => { let prefetch = ['/T0t411y-R4D-Sans'] event.waitUntil(caches.open(CURRENT_CACHE['prefetch']) .then(cache => cache.addAll(prefetch.map((url) => new Request(url, { 'mode': 'no-cors' }) )) ) ) })
  12. 12. let CURRENT_CACHE = { prefetch: 'prefetch-cache-v1' }; self.addEventListener('install', event => { let prefetch = ['/T0t411y-R4D-Sans'] event.waitUntil(caches.open(CURRENT_CACHE['prefetch']) .then(cache => cache.addAll(prefetch.map((url) => new Request(url, { 'mode': 'no-cors' }) )) ) ) })
  13. 13. let CURRENT_CACHE = { prefetch: 'prefetch-cache-v1' }; self.addEventListener('install', event => { let prefetch = ['/T0t411y-R4D-Sans'] event.waitUntil(caches.open(CURRENT_CACHE['prefetch']) .then(cache => cache.addAll(prefetch.map((url) => new Request(url, { 'mode': 'no-cors' }) )) ) ) })
  14. 14. self.addEventListener('fetch', event => { event.respondWith(caches.match(event.request) .then((response) => { if (response) { return response; } return fetch(event.request) .then(response => response); })); });
  15. 15. self.addEventListener('fetch', event => { event.respondWith(caches.match(event.request) .then((response) => { if (response) { return response; } return fetch(event.request) .then(response => response); })); });
  16. 16. self.addEventListener('fetch', event => { event.respondWith(caches.match(event.request) .then((response) => { if (response) { return response; } return fetch(event.request) .then(response => response); })); });
  17. 17. :(
  18. 18. AppCache
  19. 19. @JaffaTheCake
  20. 20. ServiceWorker > AppCache
  21. 21. ...but it covers our use case
  22. 22. if('serviceWorker' in navigator) { navigator.serviceWorker.register('/serviceworker.js') } else if ('applicationCache' in window) { // add AppCache }
  23. 23. <html lang="en" manifest="/offline.appcache"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> ...
  24. 24. <html lang="en" manifest="/offline.appcache"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> ...
  25. 25. if('serviceWorker' in navigator) { navigator.serviceWorker.register('/serviceworker.js') } else if ('applicationCache' in window) { // add AppCache }
  26. 26. let iframe = document.createElement('iframe') iframe.style.display = 'none' iframe.src = '/load-appcache.html' document.body.appendChild(iframe)
  27. 27. let iframe = document.createElement('iframe') iframe.style.display = 'none' iframe.src = '/load-appcache.html' document.body.appendChild(iframe)
  28. 28. let iframe = document.createElement('iframe') iframe.style.display = 'none' iframe.src = '/load-appcache.html' document.body.appendChild(iframe)
  29. 29. let iframe = document.createElement('iframe') iframe.style.display = 'none' iframe.src = '/load-appcache.html' document.body.appendChild(iframe)
  30. 30. <html manifest="/offline.appcache"> <head> <title>loading douchebags</title> </head> <body></body> </html>
  31. 31. CACHE MANIFEST / /download /css/main.css /img/logo.svg /js/build.js NETWORK: *
  32. 32. CACHE MANIFEST / /download /css/main.css /img/logo.svg /js/build.js NETWORK: *
  33. 33. CACHE MANIFEST / /download /css/main.css /img/logo.svg /js/build.js NETWORK: *
  34. 34. CACHE MANIFEST / /download /css/main.css /img/logo.svg /js/build.js NETWORK: *
  35. 35. 20.7 seconds
  36. 36. 190 milliseconds
  37. 37. @JaffaTheCake
  38. 38. radical new way to create web sites
  39. 39. radical new way to update web sites
  40. 40. WebWorkers
  41. 41. commit 90b52e847359ae902d3f7ce7bc511cadfbc29ea8 Author: Alexey Proskuryakov <ap@webkit.org> Date: Thu Nov 6 07:04:47 +0000 Implement Worker global object
  42. 42. 2008!
  43. 43. WebWorkers?
  44. 44. single threaded by default
  45. 45. everything is fighting for CPU time
  46. 46. lots of number crunchin’ === hardcore jank
  47. 47. Offload tasks to background thread
  48. 48. super expensive fns become pretty cheap
  49. 49. @PatrickKettner
  50. 50. @PatrickKettner
  51. 51. @PatrickKettner
  52. 52. https://github.com/nolan lawson/pokedex.org
  53. 53. Web App Manifest
  54. 54. { "lang": "en", "dir": "ltr", "name": "Super Racer 2000", "description": "The ultimate futuristic racing game from the future!", "short_name": "Racer2K", "icons": [{ "src": "icon/lowres.webp", "sizes": "64x64", "type": "image/webp" },{ "src": "icon/lowres.png", "sizes": "64x64" }, { "src": "icon/hd_hi", "sizes": "128x128" }], "scope": "/racer/", "start_url": "/racer/start.html", "display": "fullscreen", "orientation": "landscape", "theme_color": "aliceblue", "background_color": "red" }
  55. 55. { "lang": "en", "dir": "ltr", "name": "Super Racer 2000", "description": "The ultimate futuristic racing game from the future!", "short_name": "Racer2K", "icons": [{ "src": "icon/lowres.webp", "sizes": "64x64", "type": "image/webp" },{ "src": "icon/lowres.png", "sizes": "64x64" }, { "src": "icon/hd_hi", "sizes": "128x128" }], "scope": "/racer/", "start_url": "/racer/start.html", "display": "fullscreen", "orientation": "landscape", "theme_color": "aliceblue", "background_color": "red" }
  56. 56. { "lang": "en", "dir": "ltr", "name": "Super Racer 2000", "description": "The ultimate futuristic racing game from the future!", "short_name": "Racer2K", "icons": [{ "src": "icon/lowres.webp", "sizes": "64x64", "type": "image/webp" },{ "src": "icon/lowres.png", "sizes": "64x64" }, { "src": "icon/hd_hi", "sizes": "128x128" }], "scope": "/racer/", "start_url": "/racer/start.html", "display": "fullscreen", "orientation": "landscape", "theme_color": "aliceblue", "background_color": "red" }
  57. 57. { "lang": "en", "dir": "ltr", "name": "Super Racer 2000", "description": "The ultimate futuristic racing game from the future!", "short_name": "Racer2K", "icons": [{ "src": "icon/lowres.webp", "sizes": "64x64", "type": "image/webp" },{ "src": "icon/lowres.png", "sizes": "64x64" }, { "src": "icon/hd_hi", "sizes": "128x128" }], "scope": "/racer/", "start_url": "/racer/start.html", "display": "fullscreen", "orientation": "landscape", "theme_color": "aliceblue", "background_color": "red" }
  58. 58. { "lang": "en", "dir": "ltr", "name": "Super Racer 2000", "description": "The ultimate futuristic racing game from the future!", "short_name": "Racer2K", "icons": [{ "src": "icon/lowres.webp", "sizes": "64x64", "type": "image/webp" },{ "src": "icon/lowres.png", "sizes": "64x64" }, { "src": "icon/hd_hi", "sizes": "128x128" }], "scope": "/racer/", "start_url": "/racer/start.html", "display": "fullscreen", "orientation": "landscape", "theme_color": "aliceblue", "background_color": "red" }
  59. 59. { "lang": "en", "dir": "ltr", "name": "Super Racer 2000", "description": "The ultimate futuristic racing game from the future!", "short_name": "Racer2K", "icons": [{ "src": "icon/lowres.webp", "sizes": "64x64", "type": "image/webp" },{ "src": "icon/lowres.png", "sizes": "64x64" }, { "src": "icon/hd_hi", "sizes": "128x128" }], "scope": "/racer/", "start_url": "/racer/start.html", "display": "fullscreen", "orientation": "landscape", "theme_color": "aliceblue", "background_color": "red" }
  60. 60. { "lang": "en", "dir": "ltr", "name": "Super Racer 2000", "description": "The ultimate futuristic racing game from the future!", "short_name": "Racer2K", "icons": [{ "src": "icon/lowres.webp", "sizes": "64x64", "type": "image/webp" },{ "src": "icon/lowres.png", "sizes": "64x64" }, { "src": "icon/hd_hi", "sizes": "128x128" }], "scope": "/racer/", "start_url": "/racer/start.html", "display": "fullscreen", "orientation": "landscape", "theme_color": "aliceblue", "background_color": "red" }
  61. 61. { "lang": "en", "dir": "ltr", "name": "Super Racer 2000", "description": "The ultimate futuristic racing game from the future!", "short_name": "Racer2K", "icons": [{ "src": "icon/lowres.webp", "sizes": "64x64", "type": "image/webp" },{ "src": "icon/lowres.png", "sizes": "64x64" }, { "src": "icon/hd_hi", "sizes": "128x128" }], "scope": "/racer/", "start_url": "/racer/start.html", "display": "fullscreen", "orientation": "landscape", "theme_color": "aliceblue", "background_color": "red" }
  62. 62. { "lang": "en", "dir": "ltr", "name": "Super Racer 2000", "description": "The ultimate futuristic racing game from the future!", "short_name": "Racer2K", "icons": [{ "src": "icon/lowres.webp", "sizes": "64x64", "type": "image/webp" },{ "src": "icon/lowres.png", "sizes": "64x64" }, { "src": "icon/hd_hi", "sizes": "128x128" }], "scope": "/racer/", "start_url": "/racer/start.html", "display": "fullscreen", "orientation": "landscape", "theme_color": "aliceblue", "background_color": "red" }
  63. 63. "related_applications": [{ ”platform": ”play", ”url": "https://play.google.com/store/apps/details?id=com.example.app1", ”id": "com.example.app1" },{ "platform": ”itunes", ”url": "https://itunes.apple.com/app/example-app1/id123456789" }, { ”platform": ”windows", ”url": "ms-windows-store://pdp?PFN=Example.App_pfhei292v8qza" }], "prefer_related_applications": false,
  64. 64. "related_applications": [{ ”platform": ”play", ”url": "https://play.google.com/store/apps/details?id=com.example.app1", ”id": "com.example.app1" },{ "platform": ”itunes", ”url": "https://itunes.apple.com/app/example-app1/id123456789" }, { ”platform": ”windows", ”url": "ms-windows-store://pdp?PFN=Example.App_pfhei292v8qza" }], "prefer_related_applications": false,
  65. 65. <html lang=en dir=ltr> <head> <title>Racer2K</title> <meta name=application-name content="Super Racer 2000”> <meta name=description content="The ultimate futuristic game"/> <meta name=apple-mobile-web-app-capable content=yes> <link rel=manifest href="manifest.webmanifest"> <meta name=screen-orientation content=landscape> <meta name=theme-color content=aliceblue> <link rel=favicon href="icon/lowres.png"> <meta name="msApplication-PackageFamilyName" content="Example… <link rel=alternate href="ios-app://id123456789/racer/begin"> <link rel=apple-touch-icon sizes=64x64 href="icon/lowres.png"> <link rel=apple-touch-icon sizes=128x128 href="icon/hd_hi.png"> <link rel=start href="/racer/start.html">
  66. 66. <html lang=en dir=ltr> <head> <title>Racer2K</title> <meta name=application-name content="Super Racer 2000”> <meta name=description content="The ultimate futuristic game”> <meta name=apple-mobile-web-app-capable content=yes> <link rel=manifest href="manifest.webmanifest"> <meta name=screen-orientation content=landscape> <meta name=theme-color content=aliceblue> <link rel=favicon href="icon/lowres.png"> <meta name="msApplication-PackageFamilyName" content="Example… <link rel=alternate href="ios-app://id123456789/racer/begin"> <link rel=apple-touch-icon sizes=64x64 href="icon/lowres.png"> <link rel=apple-touch-icon sizes=128x128 href="icon/hd_hi.png"> <link rel=start href="/racer/start.html">
  67. 67. { "lang": "en", "dir": "ltr", "name": "Super Racer 2000", "description": "The ultimate futuristic racing game from the future!", "short_name": "Racer2K", "icons": [{ "src": "icon/lowres.webp", "sizes": "64x64", "type": "image/webp" },{ "src": "icon/lowres.png", "sizes": "64x64" }, { "src": "icon/hd_hi", "sizes": "128x128" }], "scope": "/racer/", "start_url": "/racer/start.html", "display": "fullscreen", "orientation": "landscape", "theme_color": "aliceblue", "background_color": "red" }
  68. 68. <html lang=en dir=ltr> <head> <title>Racer2K</title> <meta name=application-name content="Super Racer 2000”> <meta name=description content="The ultimate futuristic game”> <meta name=apple-mobile-web-app-capable content=yes> <link rel=manifest href="manifest.webmanifest"> <meta name=screen-orientation content=landscape> <meta name=theme-color content=aliceblue> <link rel=favicon href="icon/lowres.png"> <meta name="msApplication-PackageFamilyName" content="Example… <link rel=alternate href="ios-app://id123456789/racer/begin"> <link rel=apple-touch-icon sizes=64x64 href="icon/lowres.png"> <link rel=apple-touch-icon sizes=128x128 href="icon/hd_hi.png"> <link rel=start href="/racer/start.html">
  69. 69. <html lang=en dir=ltr> <head> <title>Racer2K</title> <meta name=application-name content="Super Racer 2000”> <meta name=description content="The ultimate futuristic game”> <meta name=apple-mobile-web-app-capable content=yes> <link rel=manifest href="manifest.webmanifest"> <meta name=screen-orientation content=landscape> <meta name=theme-color content=aliceblue> <link rel=favicon href="icon/lowres.png"> <meta name="msApplication-PackageFamilyName" content="Example… <link rel=alternate href="ios-app://id123456789/racer/begin"> <link rel=apple-touch-icon sizes=64x64 href="icon/lowres.png"> <link rel=apple-touch-icon sizes=128x128 href="icon/hd_hi.png"> <link rel=start href="/racer/start.html">
  70. 70. let cheerio = require(’cheerio') let cld = require('cld') let getLang = (html, callback) => { let $ = cheerio.load(html) let lang = $('html[lang]').attr(‘lang') if (!lang) { lang = $('html[xml:lang]').attr(‘xml:lang’) } if (!lang) { lang = $(’meta[name:”dc.language”]').attr(‘content’) } ...
  71. 71. let cheerio = require(’cheerio') let cld = require('cld') let getLang = (html, callback) => { let $ = cheerio.load(html) let lang = $('html[lang]').attr(‘lang') if (!lang) { lang = $('html[xml:lang]').attr(‘xml:lang’) } if (!lang) { lang = $(’meta[name:”dc.language”]').attr(‘content’) } ...
  72. 72. let cheerio = require(’cheerio') let cld = require('cld') let getLang = (html, callback) => { let $ = cheerio.load(html) let lang = $('html[lang]').attr(‘lang') if (!lang) { lang = $('html[xml:lang]').attr(‘xml:lang’) } if (!lang) { lang = $(’meta[name:”dc.language”]').attr(‘content’) } ...
  73. 73. let cheerio = require(’cheerio') let cld = require('cld') let getLang = (html, callback) => { let $ = cheerio.load(html) let lang = $('html[lang]').attr(‘lang') if (!lang) { lang = $('html[xml:lang]').attr(‘xml:lang’) } if (!lang) { lang = $(’meta[name:”dc.language”]').attr(‘content’) } ...
  74. 74. let cheerio = require(’cheerio') let cld = require('cld') let getLang = (html, callback) => { let $ = cheerio.load(html) let lang = $('html[lang]').attr(‘lang') if (!lang) { lang = $('html[xml:lang]').attr(‘xml:lang’) } if (!lang) { lang = $(’meta[name:”dc.language”]').attr(‘content’) } ...
  75. 75. let cheerio = require(’cheerio') let cld = require('cld') let getLang = (html, callback) => { let $ = cheerio.load(html) let lang = $('html[lang]').attr(‘lang') if (!lang) { lang = $('html[xml:lang]').attr(‘xml:lang’) } if (!lang) { lang = $(’meta[name:”dc.language”]').attr(‘content’) } ...
  76. 76. cld.detect(html,{isHTML: true},(err, result) => { if (!err && result.reliable) { lang = result.language.code } callback(err, lang) }
  77. 77. let url = require(’url') let async = require(’async’) let icojs = require(’icojs') let cheerio = require(’cheerio') let request= require(’request') let imgsize = require(’image-size') let imgtype = require(’image-type') let mime = require(’./mime-types’).lookup let FilteType = require(’file-type') let flatten = require(’lodash/flattenDeep') let filter = require(’lodash/filter') let icons = (obj, callback) => { let $ = cheerio.load(html) let favicon = $(’rel[“shortcut icon”]').attr(‘href')
  78. 78. <link rel=favicon href="icon.ico"> <link rel=apple-touch-icon sizes=64x64 href="icon/lowres.png"> <link rel=apple-touch-icon sizes=128x128 href="icon/hd_hi.png”><meta name="msApplication-TileImage" content=”icon/tile.png”> <meta name="msApplication-config" content=”tileConfig.xml”>
  79. 79. <link rel=favicon href="icon.ico"> <link rel=apple-touch-icon sizes=64x64 href="icon/lowres.png"> <link rel=apple-touch-icon sizes=128x128 href="icon/hd_hi.png"> <meta name="msApplication-TileImage" content=”icon/tile.png”> <meta name="msApplication-config" content=”tileConfig.xml”>
  80. 80. <link rel=favicon href="icon.ico"> <link rel=apple-touch-icon sizes=64x64 href="icon/lowres.png"> <link rel=apple-touch-icon sizes=128x128 href="icon/hd_hi.png"> <meta name="msApplication-TileImage" content=”icon/tile.png”> <meta name="msApplication-config" content=”tileConfig.xml”>
  81. 81. <link rel=favicon href="icon.ico"> <link rel=apple-touch-icon sizes=64x64 href="icon/lowres.png"> <link rel=apple-touch-icon sizes=128x128 href="icon/hd_hi.png"> <meta name="msApplication-TileImage" content=”icon/tile.png”> <meta name="msApplication-config" content=”tileConfig.xml”>
  82. 82. https://WebManife.st
  83. 83. <html lang=en dir=ltr> <head> <title>Racer2K</title> <meta name=application-name content="Super Racer 2000”> <meta name=description content="The ultimate futuristic game"/> <meta name=apple-mobile-web-app-capable content=yes> <link rel=manifest href="manifest.webmanifest"> <meta name=screen-orientation content=landscape> <meta name=theme-color content=aliceblue> <link rel=favicon href="icon/lowres.png"> <meta name="msApplication-PackageFamilyName" content="Example… <link rel=alternate href="ios-app://id123456789/racer/begin"> <link rel=apple-touch-icon sizes=64x64 href="icon/lowres.png"> <link rel=apple-touch-icon sizes=128x128 href="icon/hd_hi.png"> <link rel=start href="/racer/start.html">
  84. 84. https://WebManife.st/validator https://WebManife.st/spec
  85. 85. <html lang=en dir=ltr> <head> <title>Racer2K</title> <meta name=application-name content="Super Racer 2000”> <meta name=description content="The ultimate futuristic game"/> <meta name=apple-mobile-web-app-capable content=yes> <link rel=manifest href="manifest.webmanifest"> <meta name=screen-orientation content=landscape> <meta name=theme-color content=aliceblue> <link rel=favicon href="icon/lowres.png"> <meta name="msApplication-PackageFamilyName" content="Example… <link rel=alternate href="ios-app://id123456789/racer/begin"> <link rel=apple-touch-icon sizes=64x64 href="icon/lowres.png"> <link rel=apple-touch-icon sizes=128x128 href="icon/hd_hi.png"> <link rel=start href="/racer/start.html">
  86. 86. let methodData = [{ supportedMethods: [’basic-card'], data: { supportedNetworks: [’visa', ’mastercard', ’amex'], supportedTypes: [’credit'] } }]; let details = { total: { label: ’Total Due', amount: { currency: ’USD', value : ’109.00' } }}; var options = { requestShipping: true };
  87. 87. let methodData = [{ supportedMethods: [’basic-card'], data: { supportedNetworks: [’visa', ’mastercard', ’amex'], supportedTypes: [’credit'] } }]; let details = { total: { label: ’Total Due', amount: { currency: ’USD', value : ’109.00' } }}; var options = { requestShipping: true };
  88. 88. let methodData = [{ supportedMethods: [’basic-card'], data: { supportedNetworks: [’visa', ’mastercard', ’amex'], supportedTypes: [’credit'] } }]; let details = { total: { label: ’Total Due', amount: { currency: ’USD', value : ’109.00' } }}; var options = { requestShipping: true };
  89. 89. if (’PaymentRequest’ in window) { let payment = new PaymentRequest(methodData, details, options) }
  90. 90. if (’PaymentRequest’ in window) { let payment = new PaymentRequest(methodData, details, options) } else { window.location.href = ‘/old-checkout’ }
  91. 91. if (’Windows’ in window) { ... }
  92. 92. bluetooth Windows​.Devices​.Bluetooth
  93. 93. media keys Windows.​Media.​Dial​Protocol
  94. 94. ocr Windows.​Media.​Ocr
  95. 95. cortana Windows​.ApplicationModel​.VoiceCommands
  96. 96. IndexedDB
  97. 97. commit 4334db65c2718d304d4792fbeb46f96e9d798b76 Author: Ben Turner <bent@mozilla.com> Date: Wed Jun 23 19:46:00 2010 +0000 Implement Asynchronous parts of the Indexed Database API
  98. 98. localStorage.setItem(’foo', ’bar'); localStorage.getItem(’foo’) //bar
  99. 99. window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange; if (!window.indexedDB) { alert("Sorry!Your browser doesn't support IndexedDB"); } var database; var request = window.indexedDB.open("foobar",1); request.onerror = function(event) { console.log(event.target.errorCode); }; request.onsuccess = function(event) { database=request.result; }; request.onupgradeneeded = function(event) { var db = event.target.result; var objectStore = db.createObjectStore("notes", { keyPath: "id",autoIncrement:true}); }; var note={title:"foo", body:"bar", date:”06/21/2016”}; var transaction = database.transaction(["hello"], "readwrite"); var objectStore = transaction.objectStore("world"); var request=objectStore.put(note); request.onsuccess = function(event) { //do something here }; var objectStore = database.transaction("hello").objectStore("world"); objectStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if (cursor) { alert("Note id: "+cursor.key+", Title: "+cursor.value.title); cursor.continue(); } };
  100. 100. window.name document.cookie Flash Cache IndexedDB localStorage AppCache Cache API WebSQL
  101. 101. window.name document.cookie Flash Cache IndexedDB localStorage AppCache Cache API WebSQL
  102. 102. window.name document.cookie Flash Cache IndexedDB localStorage AppCache Cache API WebSQL
  103. 103. window.name document.cookie Flash Cache IndexedDB localStorage AppCache Cache API WebSQL
  104. 104. var db = new Dexie('MyDatabase'); db.friends .where(‘age’) .above(75) .each((friend) => { console.log(friend.name); });
  105. 105. localForage.setItem(’foo', ’bar'); localForage.getItem(’foo’, (err, val) => { console.log(val) } ))
  106. 106. with a G
  107. 107. demo.agektmr.com/storage
  108. 108. don’t wait for a rearch
  109. 109. use the new shiny.
  110. 110. make awesome stuff.
  111. 111. github.com/PatrickKettner twitter.com/PatrickKettner facebook.com/PatrickKettner PatKet@microsoft.com
  112. 112. Thanks!

×