JavaScriptMultithreadingEverybody knows Javascript is single-threaded and that it shares this same thread with other browser-related processes such as painting and compositing. There are several techniques to implement pseudo multithreading in JavaScript; however, during this talk we will focus our attention on how to use and debug the Service Worker API. Our end goal is to explore practical use cases in order to simplify the process to render complex user interfaces and transitions in a browser. Even more, we will focus on how to improve the user experience with not stable connectivity.
@giorgionatili
Giorgio NatiliEngineering Lead
On paper, Giorgio Natili is an engineering lead at McGraw-
Hill Education where he spearheads the accessibility and
mobile/reading experience initiatives for the company’s
LearnSmart division. On the job, Giorgio is a strong
proponent of agile development practices whose passion for
usable, maintainable and testable code is only surpassed by
his determination to make things work. In addition to
standards-based application development, Giorgio’s areas of
expertise include real-time communication and surfing off the
coast of his native Italy. His previous speaking engagements
include Adobe Max, 360|Flex, FITC, Mobile Web Dev
Conference, Mobile Tea and many other community-driven
events in both Europe and the United States.
ANDROID
IOS (SWIFT)
JAVASCRIPT
CORDOVA
TDD + BDD
WEBRTC
@giorgionatili
http://careers.mheducation.com
Performance Engineers
Automation Engineers
Software Engineers (Intern)
Software Engineers
Today’sAgenda
Offline Web Application
Why offline is not a failure, and why we should embrace offline
scenarios as an opportunity.
Service WorkersDiscover how a service worker works, understand the main
gotchas to start with, and how to use the API today, especially in
mobility.
Multithreading JavascriptExplore how to create even more scalable web apps using service
workers and how to delegate networking and other expensive
operations to “external” entities.
AdditionalThoughts
Offline Web
Applications
OfflineWebApps is an Old
Topic • Occasionally connected computing literature dates back to the 1970s.
• Macromedia tried to enable offline with Central
• A List Apart discussed these techniques in 2013
Lack of Connectivity is not an Error
• Don’t treat a lack of connectivity like an error.
• Apps should be able to handle dropped connections.
• Apps should keep minimal functionalities when offline.
Offline Statuses
Desktop
Laptops
MobileDevices
What is the most important capability shared between these
devices?
All of them can be offline!
Offline is a New
Opportunity• Designing apps and their interfaces for intermittent connectivity leads to an abundance of new scenarios and problems.
• Solving all of them means that your app should preempting users’ needs.
Review Your Architecture
Separation Of Concerns Resource OptimizationData Request Flow
In order to implement a successful offline strategy
it’s mandatory to define clear boundaries between
UI elements, logic and content.
An app is nothing without data; however, a well
organized data request flow can offer a good
experience also in offline mode.
Caching spaces are limited; optimizing images,
CSS, JS files, etc. is a very important phase of
the re-architecture.
There isn’t an app that cannot be improved. Iterating in a collaborative way over and over is the preferred way
to evolve architectures.
However, bad architectures exist. Don’t be scared to start over embracing the “offline first” approach!
Identify Clearly The App Layers
03. Bundles
Optimizing the UI for different screens means also feeding the
app with appropriately compressed images, this consideration is
the key to avoid issues with caches size.
04. User Interface
Be sure to decouple components as much as possible;
otherwise caching the dependencies will proof difficult when
implementing any strategy.
01. Communication Layer
Use the fetch API and avoid implementing a call-back pyramid
of doom; take advantage of the Promises and of their sequential
syntax.
02. Network Layer
Avoid a single bundle; breaking down the app in more than a
single monolithic bundle will be the key for a layered caching
strategy.
ThinkingOffline
Native Experience
Think to the offline re-architecture as an opportunity to handle your app as if it were a native one.
Better Functionalities
The reviewed architecture will help you to handle gracefully the points of failures (POF) of your app.
Future Proof
Handling remote requests with offline use in mind will help you to integrate the fetch API.
ServiceWorkers
Workers in a Nutshell
Web WorkersWeb workers provide a simple means for web content to run
scripts in background threads. The worker thread can perform
tasks without interfering with the user interface.
Shared WorkersA shared worker is a specific kind of worker that can be accessed
from several browsing contexts, such as several windows,
iFrames, or even workers (in the same domain).
Service WorkersService workers are event-driven workers that act as proxy
servers that sit between web applications, the browser, and the
network (when available).
A Quick Overview
• The ServiceWorkers API allows us to make sites work offline through intercepting network requests and programmatically telling the browser what to do with these requests.
• This API works in Chrome and other browsers (https://github.com/coonsta/cache-polyfill)
• chrome://inspect/#service-workers
Features
• The killer feature in the ServiceWorker API is the offline “first” nature.
• A service worker is a background worker (easy multi-threading).
• The API allows us to implement background sync, (almost) geofencing and network control.
ServiceWorkerLifecycle
• On install (as a dependency or not)
• On activate
• On push message
• On background-sync
• On terminate
Registering a ServiceWorker
let sw = navigator.serviceWorker; sw.register('service-worker.js', {scope: './'}).then(function(registration) {
// Handle the installation gracefully
});
self.addEventListener('install', function(event) { event.waitUntil( caches.open('static-v3').then(function(cache) { return cache.addAll([
'/css/whatever-v3.css', '/css/img/sprites-v6.png', '/css/fonts/whatever-v8.woff', '/js/all-min-v4.js'
// Whatever your app needs to run
]); }) ); });
Service WorkerInstallation
Not BlockingInstalling
self.addEventListener('install', function(event) { event.waitUntil( caches.open('assets-core-v1').then(function(cache) { cache.addAll(
// Optional assets ); }) ); });
Service WorkerActivation
self.addEventListener('activate', function(event) { event.waitUntil( caches.keys().then(function(cacheNames) { return Promise.all([
// It happens when the page reload or // when a new version is installed // It’s the best place to manage the caches ]); }) ); });
Service WorkerFetch
self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request).then(function(response) { // Return network with cache fallback // Basic, CORS or Opaque responses return response || fetch(event.request); }) ); });
Service WorkerNotification
self.addEventListener('push', function(event) { if (event.data.text() == 'new-tweet') {
// Handle caches and prepare the content for the view
}});
self.addEventListener('notificationclick', function(event) { if (event.notification.tag == 'new-tweet') {
// Assume that all of the resources needed to render // the 'inbox' have previously been cached
new TweetView('inbox'); } });
Service WorkerBackground
Syncself.addEventListener('sync', function(event) { if (event.id == 'update-leaderboard') { // Or whatever promise that sync the data return openBgSyncDB(); });
Security
During development you'll be able to use service worker
through localhost; however, to deploy it on a site, you'll need to set up
HTTPS on your server.
No ExtraTests
• A ServiceWorker returns eventually cached results.
• Emulating offline the tests previously written should fulfill without any extra effort.
Debugging
You can debug a service worker with the standard Chrome DevTools
(Note: debug in an incognito window)
Mobile Support
It’s Complicated!
Browsers Support
(I am really confident about IE!)
// Include SW cache polyfill importScripts("js/serviceworker-cache-polyfill.js");
SizeMatters
• Your origin is given a certain amount of free space to use as it sees fit.
• That free space is shared between all origin storage: LocalStorage, IndexedDB, Filesystem, and Caches.
• The amount you get isn't specified; it will differ depending on device and storage conditions.
Multithreading JavaScript
JavaScript is
Multithread• Tasks are scheduled so the browser can get from its internals
into JavaScript/DOM land and ensures these actions happen sequentially. Between tasks, the browser may render updates.
• Microtasks are usually scheduled for things that should
happen straight after the currently executing script, such as reacting to a batch of actions, or to make something async
without taking the penalty of a whole new task
JavaScriptSchedule in Practice
•script start
•script end
•promise1
•promise2
•setTimeout
JavaScriptSchedule in Practice
Web & Shared Workers Scenarios• Image processing• Large amount of data recovery
• Text analysis • Complex algorithms (e.g. adaptive learning)
• Game engines• Angular digest cycle (why not ?!?)
Service Workers Scenarios
• Offline applications• Performance improvement• Notifications• Background updating
01.
02.
03. 04.
WorkersBasedArchitecture
03. Service Workers
Delegate to the Workers process intensive operations
such as data parsing and massaging, expensive
network request, etc.
04. Web & Shared Workers
Split the business logic in self-contained components to help
reduce dependencies; eventually bundle together layers of the
app when it’s too complicated to reduce the dependencies.
01. Business Logic
Create a communication bridge between components
and the worker layers using events or the
postMessage API.
02. Communication Layer
Use the Service Worker(s) to handle the cache of the
shell needed to render the app also in offline mode.
Useful Links and Resources
• The offline cookbook https://jakearchibald.com/2014/offline-cookbook/• The fetch() API https://developers.google.com/web/updates/2015/03/introduction-to-fetch?hl=en• Designing offline first apps http://alistapart.com/article/offline-first• Using WebWorker with Angular https://andywalpole.me/#!/blog/142677/using-web-workers-angularjs• A simple ServiceWorker app http://blog.lamplightdev.com/2015/01/06/A-Simple-ServiceWorker-App/ • Introduction to ServiceWorker http://www.html5rocks.com/en/tutorials/service-worker/introduction/• Progressive networking https://ponyfoo.com/articles/progressive-networking-serviceworker• ServiceWorker explained https://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md • Application shell architecture https://medium.com/google-developers/instant-loading-web-apps-with-an-application-shell-
architecture-7c0c2f10c73#.9ld0u2liz • Sending an app to the browser https://surge.sh/• Hoodie use case http://hood.ie/blog/minutes-offline-case-study.html
Offline FirstSummary
Review Code, Design & ContentClearly identify code responsibilities, decouple
code from design, define the boundaries between
content and UI, etc.
Refactor & Enhance CodeClean the code, decouple components from each
other, expose clear APIs, take advantage of
Promises, etc.
Handle Network FailureDetermine what the app needs to run without network
connection, handle the use cases in Workers,
progressively enhance the cache strategy, etc.
http://webplatform.io / twitter @giorgionatili / Mc-Graw Hill Education
Thank you for your time. aAny question?