O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

Service Workers for Performance

7.717 visualizações

Publicada em

Service Workers presentation from the 2015 Velocity Conference

Publicada em: Tecnologia
  • Entre para ver os comentários

Service Workers for Performance

  1. 1. Service Workers The Practical Bits @patmeenan Patrick Meenan
  2. 2. Slides Slideshare: http://www.slideshare.net/patrickmeenan Twitter: @patmeenan (and to #velocityconf) Velocity Site, attached to session information Video: https://www.youtube.com/user/patmeenan Office Hours: Friday, May 29 from 12:30pm-1:00pm @patmeenan
  3. 3. Chrome Team @Google (performance) WebPageTest pmeenan@webpagetest.org @patmeenan
  4. 4. The Real Experts Alex Russell @slightlylate Jake Archibald @jaffathecake
  5. 5. Service Workers
  6. 6. DOM Resource Fetching in Chrome
  7. 7. DOM Resource Fetching in Chrome In-memory Resource Cache
  8. 8. DOM Resource Fetching in Chrome In-memory Resource Cache Resource Fetcher
  9. 9. DOM Resource Fetching in Chrome Resource Fetcher Net Stack
  10. 10. DOM Resource Fetching in Chrome In-memory Resource Cache Resource Fetcher Net Stack Disk Cache
  11. 11. DOM Resource Fetching in Chrome In-memory Resource Cache Resource Fetcher Net Stack Net Disk Cache
  12. 12. DOM Resource Fetching in Chrome In-memory Resource Cache Resource Fetcher Net Stack Net Disk Cache Service Worker SW Added and Removed Here!
  13. 13. Capabilities Sees every request for your document - Including cross-origin - And headers Can synthesize responses Supports fetch Has a programmable cache and Indexed DB
  14. 14. Limitations HTTPS documents only Not active for first view iFrames are separate documents Non-CORS Cross-origin responses are opaque No global state - or concept of a “page” No Sync API’s (localstorage, XHR, etc)
  15. 15. http://memegenerator.net/instance/62336209
  16. 16. Registering if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/my-app/sw.js', { scope: '/my-app/' }); } https://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md
  17. 17. Registering if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/my-app/sw.js', { scope: '/my-app/' }); } https://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md
  18. 18. Registering if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/my-app/sw.js', { scope: '/my-app/' }); } https://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md
  19. 19. Registering if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/my-app/sw.js', { scope: '/my-app/' }); } https://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md
  20. 20. Install / activate self.addEventListener('install', function(event) { event.waitUntil( fetchStuffAndInitDatabases() ); }); self.addEventListener('activate', function(event) { // You're good to go! }); https://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md
  21. 21. Network Intercepting self.addEventListener('fetch', function(event) { event.respondWith(new Response("Hello world!")); }); https://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md
  22. 22. Enough Theory – Let’s Use It
  23. 23. Offline Content  Most benefit for Single-Page Apps where app/data are separated  Service Workers become progressive enhancement for offline support
  24. 24. Offline Content  Pre-cache offline content  Pass live requests through when online - Caching the responses  Serve cached responses when offline (if available)  Serve offline-specific versions otherwise
  25. 25. Offline Content – Pre-caching self.addEventListener( ‘install’, function(event) { event.waitUntil( caches.open(‘my-offline-cache-v1’).then( function(cache) { return cache.addAll([ ‘/site.js’, ‘/images/offline.png’, ‘/offline.html’]); }));});
  26. 26. Offline Content – Pre-caching self.addEventListener( ‘install’, function(event) { event.waitUntil( caches.open(‘my-offline-cache-v1’).then( function(cache) { return cache.addAll([ ‘/site.js’, ‘/images/offline.png’, ‘/offline.html’]); }));});
  27. 27. Offline Content – Pre-caching self.addEventListener( ‘install’, function(event) { event.waitUntil( caches.open(‘my-offline-cache-v1’).then( function(cache) { return cache.addAll([ ‘/site.js’, ‘/images/offline.png’, ‘/offline.html’]); }));});
  28. 28. Offline Content – Pre-caching self.addEventListener( ‘install’, function(event) { event.waitUntil( caches.open(‘my-offline-cache-v1’).then( function(cache) { return cache.addAll([ ‘/site.js’, ‘/images/offline.png’, ‘/offline.html’]); }));});
  29. 29. Offline Content – Pre-caching self.addEventListener( ‘install’, function(event) { event.waitUntil( caches.open(‘my-offline-cache-v1’).then( function(cache) { return cache.addAll([ ‘/site.js’, ‘/images/offline.png’, ‘/offline.html’]); }));});
  30. 30. Offline Content – Fetch Processing self.addEventListener( 'fetch', function(event) { if (navigator.online) { event.respondWith( onlineRequest(event.request) ); } else { event.respondWith( offlineRequest(event.request) ); } });
  31. 31. Offline Content – Fetch Processing self.addEventListener( 'fetch', function(event) { if (navigator.online) { event.respondWith( onlineRequest(event.request) ); } else { event.respondWith( offlineRequest(event.request) ); } });
  32. 32. Offline Content – Fetch Processing self.addEventListener( 'fetch', function(event) { if (navigator.online) { event.respondWith( onlineRequest(event.request) ); } else { event.respondWith( offlineRequest(event.request) ); } });
  33. 33. Offline Content – Fetch Processing self.addEventListener( 'fetch', function(event) { if (navigator.online) { event.respondWith( onlineRequest(event.request) ); } else { event.respondWith( offlineRequest(event.request) ); } });
  34. 34. Offline Content – Fetch Processing self.addEventListener( 'fetch', function(event) { if (navigator.online) { event.respondWith( onlineRequest(event.request) ); } else { event.respondWith( offlineRequest(event.request) ); } });
  35. 35. Offline Content – Online Response function onlineRequest(request) { return caches.match(request) .then(function(response) { … } ); }
  36. 36. Offline Content – Online Response function onlineRequest(request) { return caches.match(request).then(function(response) { if (response) { return response; } else { return fetch(request); } }); }
  37. 37. Offline Content – Online Response function onlineRequest(request) { return caches.match(request).then(function(response) { if (response) { return response; } else { return fetch(request); } }); }
  38. 38. Offline Content – Online Response … var fetchRequest = request.clone(); return fetch(fetchRequest).then( function(response) { var responseToCache = response.clone(); caches.open(CACHE_NAME).then( function(cache) { cache.put(request, responseToCache); }); return response; });
  39. 39. Offline Content – Online Response … var fetchRequest = request.clone(); return fetch(fetchRequest).then( function(response) { var responseToCache = response.clone(); caches.open(CACHE_NAME).then( function(cache) { cache.put(request, responseToCache); }); return response; });
  40. 40. Offline Content – Online Response … var fetchRequest = request.clone(); return fetch(fetchRequest).then( function(response) { var responseToCache = response.clone(); caches.open(CACHE_NAME).then( function(cache) { cache.put(request, responseToCache); }); return response; });
  41. 41. Offline Content – Online Response … var fetchRequest = request.clone(); return fetch(fetchRequest).then( function(response) { var responseToCache = response.clone(); caches.open(CACHE_NAME).then( function(cache) { cache.put(request, responseToCache); }); return response; });
  42. 42. Offline Content – Online Response … var fetchRequest = request.clone(); return fetch(fetchRequest).then( function(response) { var responseToCache = response.clone(); caches.open(CACHE_NAME).then( function(cache) { cache.put(request, responseToCache); }); return response; });
  43. 43. Offline Content – Online Response … var fetchRequest = request.clone(); return fetch(fetchRequest).then( function(response) { var responseToCache = response.clone(); caches.open(CACHE_NAME).then( function(cache) { cache.put(request, responseToCache); }); return response; });
  44. 44. Offline Content – Offline Response function offlineRequest(request) { if (request.url.match(/.png$/)) { return caches.match(‘/images/offline.png’); } else if (request.url.match(/.html$/)) { return caches.match(‘/offline.html’); } … }
  45. 45. Offline Content – Offline Response function offlineRequest(request) { if (request.url.match(/.png$/)) { return caches.match(‘/images/offline.png’); } else if (request.url.match(/.html$/)) { return caches.match(‘/offline.html’); } … }
  46. 46. Other Uses Not limited to applications designed for offline/SPA Legacy apps + fetch intercept = Awesome possibilities
  47. 47. Custom Error Pages Fetch Request Normally For non-200 responses serve a local error page Not just server errors: - DNS failures - CDN/Proxy Errors - Intermediaries
  48. 48. SPOF Prevention Identify requests of interest - 3rd -party javascript - Fonts Set a timer Pass fetch requests through If timer expires before fetch completes generate error response
  49. 49. CDN/Origin Failover Identify CDN requests by URL Set a timer Pass fetch request through If timer expires, create fetch request to origin Respond with first fetch request to complete
  50. 50. Multi-Origin/CDN Identify CDN requests by URL Replace CDN domain with alternate CDN (or origin) Keep track of performance by origin Prefer faster origin (keep measuring) Could also race the CDNs in parallel - Be careful about increased data
  51. 51. Stale-While-Revalidate Respond with local cached resource - Ignoring Expires, max-age, etc. Pass fetch request through in parallel Update cache with new response Works best for known resources (analytics/ads JS, etc)
  52. 52. Prefetch Custom response headers with prefetch resources When idle, prefetch suggested resources
  53. 53. Resource Prioritization/Scheduling Track in-flight requests Make scheduling decisions as new requests come in Custom application-aware scheduling logic - Delay JS if it is known to be at the end - Delay footer images - etc
  54. 54. Delta Compression Delta compression for build->build updates - Include version in URL scheme - Get latest version number from cache - Request delta from server - Apply patch - Cache new version New compression algorithms
  55. 55. Custom Compression New compression algorithms - Brotli - Fractal image compression - JSON-specific dictionaries - Application-specific Prove-out new algorithms before standardizing …as long as it can be implemented in JS and code size is reasonable
  56. 56. Incremental Progressive Images Identify JPEG image requests from known origin Synthesize response Range request (or smarter) for first few scans Stream initial range into synthesized response Range request for remaining image (some point later) Append remaining data into synthesized response
  57. 57. Drawing Images Locally  930 x 11,362 px WebPageTest waterfall  351KB compressed PNG  42 MB in-memory (server) to generate  < 20KB compressed JSON data to describe  Prefer actual images for WPT waterfalls for easier embedding - Otherwise SVG, Canvas or DOM would work
  58. 58. Drawing Images Locally* Identify appropriate requests (i.e. waterfall.png?...) Fetch data necessary to draw image Draw to canvas Extract as PNG Synthesize PNG response * Work in progress, coming soon
  59. 59. Metrics/Debugging Pass all requests through Passively observe timings and success Report metrics back Gives visibility into failures and requests that are in flight - Unlike resource timing
  60. 60. And there’s more…
  61. 61. Required for… Push Notifications - https://gauntface.com/blog/2014/12/15/push-notifications-service-worker Background Sync - https://github.com/slightlyoff/BackgroundSync/blob/master/explainer.md GeoFencing - https://github.com/slightlyoff/Geofencing
  62. 62. Availability Chrome Stable (40+) Opera (27+) Firefox (Nightly)
  63. 63. Composable Service workers can “importScripts” Begging for a framework to handle pluggable pipeline - With compatible plugins for processing - Delta compression + scheduling + Stale While Revalidate… - Just a matter of importing the libs
  64. 64. Thank You! @patmeenan pmeenan@webpagetest.org

×