 ServiceWorker is a very big new capability in a browser and it's actually quite challenging to even talk about it. When I started putting together the slides I realized that really you can have an entire track on this thing at this entire conference. So I'm going to do something that I usually try to avoid doing, which is I have a lot of code in the slides and we're going to walk through it. I will share the slides at the end so don't feel like you have to rush and kind of wrap your head around it all. But I think the best way to illustrate some of the capabilities is to actually see the code because I drew a lot of diagrams but then I realized it's a little bit hand wavy. You kind of get it but you don't really feel like you're actually doing it, which is why I'm going to go with the code. But before we do that, let's talk about what are we trying to solve and what is the ServiceWorker thing because I figure some of you have probably read about it, some of you may not even have heard about it before. So the typical flow today is you have a phone, you type in the URL and we send a request to your example.com and get a 200 back. And the browser starts parsing the data and then starts sending out other requests for the CSS, for the other widgets on the page and all the rest. Nothing surprising here. And at high level what you have is kind of the renderer process at the bottom, which is the thing that's rendering the page doing all the parsing. And then you have a network process that lives inside the browser, which is independent typically, that actually gets like the IPC calls that says I need to fetch this thing. So with ServiceWorker, the way this picture changes, if you look at the bottom here, is basically we're injecting another process. It's a standalone process. It's a worker process if you're familiar with web workers. So it runs on a separate thread and it's independent of the renderer process. So it actually doesn't have access to the DOM. You can't query like, you know, find element by ID. But it gives us interesting capabilities. And in particular, every request is routed through the ServiceWorker. So let's see what this actually means. When you make the request for get app HTML, we will actually spin up the worker and send that request. At which point you can actually do a variety of things as you will see and we'll work through a couple of examples. In this case, let's say we actually forwarded to example.com and kind of give it back to the renderer. So really it's a no-op. We're just forwarding requests back and forth. Then we get a request for a style of that CSS. And at this point the ServiceWorker could actually respond by itself. It could actually just terminate this connection or the request and say, fine, I have it cached or I'm going to synthesize a response and I'll give it back to you. And perhaps the most surprising thing about ServiceWorker for a lot of people is that it also sees third-party requests. So if you're requesting a widget on your origin, you will also see the request for the third-party widgets, which means that you actually have some control that you can post controls on what those requests are, how those requests are fulfilled, what kind of performance characteristics they have, caching controls and all the rest. So this is kind of like a very high-level thing. We'll work through these in details, but this is what we've covered so far. It's a worker process that runs on a separate thread, so it's independent on the renderer. It has actually an independent lifecycle, so it does not live, it is not attached to the renderer. It could actually live beyond the renderer and it can also just run in the background, independent of the renderer. So it's effectively a script that you register for your origin that says there's this worker associated with this origin and it can be started in the background. And really it's a forward proxy. And as you'll see, it mediates all the connections between the network and the renderer. So without all the way, let's get the elephant out of the room here. Where is it supported? What's the status? It's actually kind of a complicated question because ServiceWorker is not just one API. It's actually a collection of new capabilities in a browser. There's things like the Fetch API, the Streams API, there's push notifications. There's all kinds of stuff that kind of gets, that you need to enable all of this. There are various browsers that are at various stages of implementing these capabilities. So if you want the leading edge in terms of the capabilities and all the rest, you will be playing with Chrome today. Firefox has implementations of the stuff as well. It's lagging a little bit behind, but not so much behind. The IE team has indicated that they're supported. It's not yet implemented or available, but based on their feedback, it sounds like it's something they're considering. And the one unknown right now is Safari. But as you can see, for some of the other things, some of the other capabilities like promises, Fetch API and others, you kind of get a mix from different browsers. So some of the things we will discuss here, you'll have to check in different browsers. But at a very minimum, all the examples I'm going to show you will definitely work in Chrome, Chrome stable and Chrome mobile. So what is this thing? How do we register it? It's a regular HTML angle brackets. And ServiceWorker is effectively an upgrade and an install process that you kick off in the background. So somewhere on your page, you will have this embedded, which basically says, first test if ServiceWorker is supported, because otherwise just exit and don't do anything. And if you do, let's register a worker. The worker has to live on the same origin. So in this case, we're just registering the V1 SWGS. And you can also specify a scope. So by default, when you register a worker, it takes over the entire scope, the entire origin, like slash star, effectively. But you can actually have multiple workers that are responsible for separate parts of your scope. So say you have different apps running under different subdirectories, you can actually register different workers for that and kind of have them cooperate and do all that kind of thing. So that's scope. And then if the registration is successful and by successful I mean you fetch the ServiceWorker script, we parsed it and we kind of started executing it, we will call the registration succeeded. So at least you know that this thing is in the background. It's important to know that this is completely asynchronous. So you can drop this snippet into your page. The page continues to load as a so you're basically adding this as a progressive enhancement. And the registration runs in the background and we try to keep it low priority in the sense that we don't want this thing to interrupt your actual browsing experience. So as a user you should not see anything. There's no prompts coming up right now saying like hey somebody's trying to install ServiceWorker, would you like to accept? This just runs in the background, just like any other asynchronous script. So then what happens is the user loads the URL and they start using the page. Nothing has changed for the user. In the background we start the register process and when the worker is started we call it a worker in waiting. So there are a couple of steps that need to happen before the worker actually takes over and starts receiving a request. So in particular we fire two events. There's the uninstall and onactivate. And let's take a closer look at each one of those. So uninstall is an event that fires within the worker itself. So this is content that would live inside of your worker script itself. This is the first callback that you get when we fetch the actual script and start executing saying like hey we're installing you. What do you want to do? It's plausible you just say nothing. I'm just going to exit immediately. But more likely you can actually now script your install process. Your install process, this is interesting. This is new capability in the browser. We actually give you access to managing your own caches. So we have a new cache API where you can actually declare your own caches and put things in there. So you're literally installing the application to work offline. I need to download the CSS. I need to download the data JSON file or whatever else. And I'm just going to cache it. So what we're doing here is we're opening a new cache which is my app v1, whatever name you want to give it. And then we say add all these files and add all is part of the API which just provides a bunch of paths. In the background this will actually go out and fetch each one of those files and place them in the cache. And you can see how we can fetch them later as well. So the way to think about this is the user did not click the install button. But in the background we're pre-fetching or caching all of these things as the user is interacting with the page which is quite cool if you think about it. And it's completely scriptable. So you can download the bootstrap logic and then defer some other downloads until later. So here's a fun slide. I took this directly from the spec. You can read the service worker spec. That's where the new cache interface is defined. So as you can see here, it's actually exposed to the worker process and the window process. So you'll actually be able to query the cache from the document itself also. But the kinds of capabilities you have are match. That's what you would use to check if something is in cache. You can iterate over the entire cache. You can see everything that's in there. You can delete things from cache, you can put things in cache, all the things that you would expect. And for things like match where you say, is there a thing in my cache instead of iterating manually, you can provide some additional parameters like ignore the method or ignore the very string or ignore the query parameters for this thing. So that's not to say that this is the end all of the cache API, but that's where it is today. I can make suggestions for how we can improve this. But in a nutshell, it allows you to put things in cache, extract them from cache, and iterate over the cache. Which of course is something that developers have been asking for a long, long time. So next, we've done install, at which point you've probably prefetched some files, you put them into your cache. Next, we actually dispatch the activate event. And the activate event fires when all the other previous workers have gone away to reload the page. So this is important. We intentionally made the worker registration process asynchronous such that you can't block the entire page load on registering a service worker. We want to make sure that pages continue to be built in such a way that they can be viewed without service worker. But they can be enhanced by adding this capability. So you install the worker and then the user has to effectively reload the page. There's actually a small escape clause to do a couple of methods that allow you to claim the page immediately. But it's kind of like an advanced future that I'm not going to cover here. It is in the spec, so if you're interested, you can cover it. But let's say the user has visited the page, you got the uninstall event, you fetched your things. Next time the user visits the page or reloads the page, if there's no active, previously active workers, because it could be the case that you've registered a worker before, the version one, the old cache. So we actually wait until all the other ones have gone away, like all the pages that are currently managed by the old worker have been closed. And then we fire the onActivate. And onActivate is the first time that the worker becomes active. So you say, okay, I've just deployed version two of my worker. Version one was here previously. Let me purge my old caches. Let me upgrade the schema of my whatever database or data store. Let me do something that I need to do with my old or version one to version whatever. So here, for example, I'm showing you that I'm going to grab my caches. I'm going to walk over all of my caches and I'm going to provide some function that will filter out like return true for all the things that need to be deleted out of the cache. And then finally I will call caches delete on each one of those. So this is just a very simple demo of me purging my cache on this Activate event. So let's say all of that now is done and the user is loaded the page, we start the renderer and we start the service worker. So those two things, when the user types in the URL, now there's actually two things happening. We start the worker and we start the renderer and the request for the actual page gets sent to the worker immediately. And you can respond to it in any way you like and all requests after that will be routed through the service worker. So it mediates all communication with the network which is what you need to enable offline and other capabilities because you want to be able to fulfill requests without necessarily being connected. So here's an example. This is kind of the bread and butter of service worker. Once you've done all this work, this is all kind of ceremony, this is what we're all after in the end. You have the fetch event, the on fetch. This gets fired within the worker anytime there's a new request being made by the renderer or by the page. You get an event and the event has a request property which contains all the metadata about the request that we're about to make. Maybe that's coming from an image tag, maybe that's an XHR, maybe that's something else. It could be anything. And as you can see, you can inspect all the properties, the URL, the method, the headers and decide what to do with it. And once again, this also works for cross origin requests. I think it's important to stress that time and time again really enables some interesting capabilities. So this may seem like all really high level and kind of interesting, but I know that for me the real aha moment came when I was able to just set a break point in my service worker and effectively break point the browser on when it makes a request. Not in my code but in my service worker. So here's an example. This is actually the Chrome's new tab page uses service worker under the hood. So if you want, you can just actually go to service worker internals and inspect it and set a break point in there in fetch. So just to play with it. And as you can see here, I'm inspecting event request and it has the method, the type of the security mode, the URL you can iterate over the headers. It has all the metadata about the request. So it's as if you have a proxy that just received the request except it's living on the client. Which is pretty cool. So with that, let's actually try and do some interesting things with fetch and before my battery dies too. So we saw the on fetch. This is kind of a no-op request. In fact, if you don't specify an on fetch handler in your service worker, this is exactly the behavior that you're going to get. So you can just omit this entirely. But we're going to build this up. So what's happening here is for each fetch we want to respond with and in this case we're just saying okay, well I'm going to respond with a fetch which will fetch the request which is I'm just going to pass this along to the network process. That's all we're doing here. So a no-op not interesting but instead of doing a fetch we could actually synthesize a response. So there's actually a new response API or class where you can say well I'm going to create a response and I'm going to say hello world and I'm going to pretend like it was a 200 years. Now this is a terrible idea for obvious reasons because we're just going to respond with a hello world to every single request regardless of what it is but it kind of shows you the power. This is a powerful foot gun if you're not careful. So I expect some people will be maimed in the process but in the end it's all good. We'll learn. So we can generate and we can synthesize responses and we'll see how powerful this becomes later. Let's do something more interesting. So instead of just doing one or the other we're going to say okay we cached some things before. So the first thing I'm going to do is check if I have the request in my local cache. So I'm going to call caches.match for that request and matches that API that I showed you before which accepts a request object and looks if that thing is available in the local cache. If it's available or run the match and let's grab the response from the cache. If we get a response from the cache just return it but if the response is empty do the fetch right. So this is basically saying do a local cache lookup if it's available return it otherwise just pass it to the network pretty simple. This is where things start to get more complicated and as you'll see the font size will get smaller and smaller and smaller. So once again we're going to respond with let's do a read through cache this is our goal here let's check the cache we'll check for the cache response if there's a cache response we will return it nice and simple. This is exactly what we had before if we don't have a cache response let's do a fetch because we need to get the actual data and we'll grab that response and once we have the response we'll open the cache and put it into the cache that's the next step. The operations here are asynchronous which is why we're getting this nesting so we're saying get the response open the local cache put it into the cache and once you put it into the cache return the response so you could actually change this a little bit you don't necessarily have to put it into the cache before returning it so you could have returned it and then put it into the cache but in either way what this is doing is populating the cache as we're going to request the same URL it will just get served via this clause right here so it's a very simple implementation of a read through cache and obviously it can be arbitrarily complex or simple in this case you can check for the URLs and decide which ones you want to cache or maybe not okay so let's do something else what if we want to handle errors what if our back end goes down and we get a 500 back wouldn't it be nice to gracefully recover from that well it turns out that's actually fairly simple as well so what we're going to do here is we're going to default to going to the network first so we're going to do a fetch event.request so we're immediately dispatching it to the network and then we're going to do the read through cache pattern we're going to open the cache and check the response that we got and actually I just realized I have a small mistake so this should say response not R right so this is the response if the response is .ok just checks if it's a 200 is the status code 200 if it's 200 sorry if it's not 200 then look in my cache for the previously cached version and return it so we're returning stale data and otherwise if it was successful put it into the cache update the cache with the newest version and return it back to the renderer right so this places no bound on how long we will return the stale data it just says I will return stale data if I get a 500 or 400 or something anything that's not ok effectively and obviously you can extend this with your own time at logic and other things so once again you can customize this I'm not going to show an example of stale while revalidate which is you want to return the data immediately and fire off a revalidation request so you're not blocked on that but that's very simple to implement with this scheme as well you always default to returning the cached entry and then in the background we check does this thing need to be revalidated or updated and then just let me run that in the background which is kind of nice so you always guarantee the fast response but then on a second reload you're going to get more up to date data now we're getting into kind of the fun territory so as we said you can enforce these things by just going out for third parties so what does that mean well let's say I have a thirdparty.com with which maybe I'm not terribly happy and I would like to enforce an SLA on them like a timeout for how fast they need to return data we can do that so the way to do this is we're actually going to set up a race so promises is a new API and it has a race function which accepts an array of promises and the race is finished when any one of those promises is itself resolved so what we're going to do is we're going to set up a race and I'm going to fire off the request we check that this is thirdparty.com so we know that this request is for a third party and we're going to start the fetch and we're going to race that against another promise which will get resolved after a thousand milliseconds so this promise is just doing a set timeout and it will resolve with a new response that is actually a 408 response code which is a request timeout arguably you could do much more interesting things here like fall back to the cached entry or one of the previous strategies that you saw maybe you don't want to just blindly like you failed but you could enforce an SLA and say well I'm willing to run this for 500 milliseconds but after that I'm going to fall back to the cached entry or something like that but kind of an interesting pattern that we had access to before I know that Patrick has done a lot of talks in the past about single points of failure where you have a single script that often you do not own that can bring down your entire page and block rendering so now you actually have control over that and you can actually set granular timeouts and other things for all of your providers and of course this kind of goes without saying but I hope that by this point it's kind of obvious that you do offline pretty easily because you don't actually even have to go and make the fetch request and do a timeout we do have APIs in the browser that will tell you if you're online or offline so you can query and navigate or online and it will turn false if we know that the user is properly offline there are still edge cases where you have the li-fi case where we think you're connected you are connected but you're not quite connected it takes the request a while to timeout and that's where the timeout strategies really start to kick in and you can see how you can layer these things so you should check for navigator.online and respond with cache data maybe you actually want to render out a slightly different version of your app to indicate to the user that hey we're offline put up some prompts disable some features do some other things and then update the data once the user comes back online so navigator.online is actually available in worker process, in service worker and within your page so you can use that so that was a little bit about fetch and hopefully that gives you a flavor this is not by any stretch a comprehensive list of the things you can do but I think it kind of expands your horizons for the kinds of things that it's plausible to do now let's talk about some of the architectural bits because I think this enables service worker enables some pretty interesting patterns that we have just been able to do before so for example the current page the way we construct the page is you make the request, you get the CSS maybe there's a CDN in there and we talk a lot about the critical path it's your HTML it's your JavaScript and your CSS just to get something visible to the screen and at the end of the day you're at the mercy of the RTT to the closest edge because hopefully you've moved that data but hey, sometimes the RTT even if you've moved the stuff to the edge it's still pretty high I'm on a bad Wi-Fi connection or a 2G connection that's still a poor experience I'm still going to sit there for at least a couple of seconds staring at a blank screen well with service worker he can move the content from the edge server literally onto the device and if you think about it to do offline apps that's what you have to do is render stuff on the client so once you make that leap and once you assume that that is the new default mode of how you need to build your apps a lot of things start to become a lot more interesting so for example, this application was built by a co-worker of mine J.Carchable, so you can actually check it out online if you search for trained to thrill, it's just a demo application for service worker as you can see here, I know it's a little tiny I'm using the Chrome emulation offline and I'm reloading the page and you can see in the filmstrip that the page is still rendering within 200 milliseconds and that's because the way he's implemented it is all of the templates are stored locally so the requests go out, the service worker gets the request they return the local templates and he even caches some of the third-party content here which is images from Flickr so he's using the write-through pattern and he's cached those things some of the requests still fail but it's nonetheless functional and it comes up within 100 milliseconds and it doesn't matter what connection type you're on because you're fetching this data from local cache which is quite nice and powerful so the way to think about this is let's say you're trying to fetch a fragment of a page, right, maybe it's a review or something, a news article or maybe it's the entire page itself you request the HTML for the fragment, that request gets to the service worker that says that you need to pass that request for the same content type the renderer is expecting the HTML back but you may turn around and say, that's fine I can do that but really, I already have the template and what I need to do is fetch the data that powers that fragment so I'm going to rewrite this request and fetch the JSON data bring it into my service worker run my templating logic and return it back because we have this new response API which is really quite cool and I think I'll give you an example, an application but let's actually see how to make this work so we get the fetch event and we're going to respond with a promise.all and a promise.all is a promise that gets resolved when all of the promises are resolved so instead of a race which finishes whenever one of them finishes we're going to wait for all of them and there's two things that we're going to do we're going to do a fetch for the template so this is going to query the local cache and then in parallel we will actually send a fetch out to the network for the JSON so I'm using an example here I'm just appending a .json obviously you can do smarter things you can rewrite the URL you can define it to be whatever you want and in both cases we're returning the responses so the outcome of this promise.all and in this latter part the then function waits until the promise.all is resolved and we pull out the template and the data and we create a new response and that response is going to render the template which is going to take the template and the data and we're going to return back an HTML document so this shows you an example of you get an HTML response you go on fetch whatever you need to fetch, you template it you compose it, you stream it and you return it back to the client which is really quite cool so here's a really cool example that Pat shared at velocity Santa Clara when he was giving his service worker talk and this is specific to web page test so web page test generates these really nice and handy waterfall charts some of which are quite long so this one is about 11,000 pixels long there's a lot of requests on this page and it actually generates a 350 kilobyte image this is the PNG it takes 42 megs on the server just to generate this image on the fly but the actual data to generate this image is about 20 kilobytes compressed this is basically text this is your waterfall data wouldn't it be nice if we could transfer the 20 kilobytes of data instead of 350 kilobytes of data in this case so the reason that Patrick is generating images is because they're easy to share and people like to just copy the image paste it into an email or somewhere else so we don't want to preserve that functionality but nothing stops you from fetching this data in JSON format and actually using Canvas or some other API to generate the image directly on the client which is really quite cool and in this case you would get significant savings in terms of the data transfer you would be out for things like CPU usage on the client obviously if you're generating massive images but you could be smart about that too so the fact that we can decouple the request that the renderer makes from what actually gets fetched from the network is really really powerful here's another example of where this could come in handy in validations or updates so we have our beautiful style sheet however many kilobytes long the designer comes along and changes one color in that style sheet saves it and all of a sudden we have to refetch the entire style sheet which is kind of silly right surely there's a better way to do this and there is right we already versioned all the assets so with service worker we can actually fix this and interesting enough I actually done some analysis on HSP archive data where I looked at two runs of HSP archive about a month apart from the CSS files so for the CSS files that have changed 97% of their content was identical to the content from a month prior so 3% has changed but the browsers were forced to refetch all of the CSS so how could we do this well I hope this pattern is already starting to become familiar we're going to do a cache match for the request and in this case I'm giving an example of more the query string which is if you remember my previous slide I was actually using version query string to version the CSS so I'm just saying forget the version just like fetch whatever you have for this file name which is style let's CSS fine let's get the old response and let's get the content out of it so that's the text and I'm also going to do an MD5 hash of the content because I can I have access to the content and instead of just requesting it I'm going to request the URL and pass to the origin the cache of my current version so I'm just basically doing a fingerprint like here's a thing that I have in my cache you could also just add this into the headers if you so prefer and then wait for the response back and then finally I'm assuming that here we're using something like a VC diff which is simple enough to do on the server I'm going to compose a new response back to the client which is going to take the old content the old version and the new diff so I'm basically taking the old content the diff running VC diff decode on it to create the new version and just returning it back to the client I'm skipping one step here just because I'm running out of space which is I should write this back into the cache but you can refer back to one of the earlier examples so all of a sudden there's many different implementations that you can substitute here and it's actually quite interesting because you can actually imagine deploying different or own or custom diff formats you can fetch your own image format and transcode it once again be careful with CPU usage but you could you can generate images you can use any diffing algorithm you like you can even ship git patches if you want so that's kind of cool but different which is we can also make the service worker content aware so everything we described so far has worked on a level of a request we really haven't taught anything about the global knowledge of the app that it's executing but nothing stops us from doing that as one example we can do prefetch we can implement our own prefetching logic so for example let's say we have an article and that article is split into multiple pages and I want to prefetch the next page as the user is reading the current one well that's pretty simple because once again we get the fetch event for the article and we're going to check the path for that and then we're going to say fine if we're getting a request for the article let's also fetch the part 2 of this article and place it in cache so some of the code just insert some of the code that we saw earlier but then this is going to happen in the background this is not going to block us from returning the current response so let's continue and down here we will match the original request and return from the cache or fetch it from the network so we're composing some of the patterns that we've seen before so all of a sudden you have custom prefetch logic that you've just implemented obviously the browser has some of its own smarts and some of its directives that allow you to avoid doing a sort of work but nothing stops you from making the browser much smarter about the way it does prefetch and by the way you would also see prefetch and preload and other requests being routed through the service worker so if the user agent itself initiates one of those requests all the same logic applies and you can actually distinguish them here you'd be able to say you can look at who initiated the request and it would say prefetch has initiated this request and you can do something smart about it whatever that may be here's another example that I think is kind of cool so with service worker we can make the image tag very, very smart so of course we've all heard that we have the picture tag now and you can do all kinds of art direction and high resolution or multi resolution use cases but I really like the image tag like the one liner where you just say I want this image, it's nice and simple I really like that for some reason so in Chrome we support client hints which you enable by adding this meta directive in your page and what this tells the browser is to enable client hints and send the device pixel resolution the viewport width and the width of the asset when it's known the display width of the asset so stay with me so say we enable this and we have the image tag which is image.jpg and it's 500 pixels in the service worker so this is actually an example of me setting a break point in the service worker and just iterating and dumping all of the headers on that request when the renderer makes it you see that we're making a request for an image file we see the accept headers which advertise that hey Chrome supports WebP you might want to serve a WebP image and also by the way in this case I should have made this 360 to line up and make it more clear but the width is the width of the asset as it's intended to be displayed the renderer does not always know this value but when it does it can advertise it and say this image at 500 pixels wide and the device pixel resolution is 2 and the viewport with the layout viewport with is 720 so all of a sudden this image tag becomes or can become aware of the resolution and the width and everything you can rewrite this request and put those parameters into the URL or you can send them via headers and have your image back end so that maybe it's a CDN maybe it's your own home cooked version respond with the right asset so this image tag is all of a sudden can serve 2x resources without you needing to rewrite all of the existing markup which is really quite nice so really the take away here is there's just a lot of different patterns this barely scratches the surface which is why I said that we really need a whole track on this we could probably do a deep dive just the cache and validations and how to work with the cache so I expect to see a lot more content about this at future velocities for sure but there's more and this is the really ambitious and interesting part about service worker we talked about fetch and how it interacts with when the renderer is active but the service worker can actually live beyond the renderer and independent of the renderer which is kind of mind bending so let's see what that actually means for example you're offline and you want to queue up a bunch of requests like the client or the user is doing something with your app and you're trying to record that fact and you know you're offline, fine so you take those fetch requests and you just start accumulating them but then ultimately you would like for those requests to go out when the user is back online but how do you know that they're back online and then you do something else so we provide the on-sync event which is automatically triggered when the user agent transitions from offline to offline to online and there's no requirement for the page to be active at that point which is really interesting, right because you could have interacted with the page, you recorded all the things you've gone away, you put your phone into your pocket you walked out outside their service, we wake up the worker or Chrome will wake up the worker and say what do you want to do, right and at that point you can flush your request you can fetch data to get new updates or anything you like, which is really quite cool next up this is not service worker specific but now that we're talking about offline apps, we can actually put ourselves onto the home stream we are an app, right, we don't need network access so we have the manifest spec which is just this JSON file that you see here basically tells you what's the name of the app give me some nice looking icons and you do need a service worker so if you put this into your page all of a sudden the Chrome when you come and visit the page will throw up a prompt to the user and say hey would you like to add this thing to your home screen and once it's on your home screen it looks and feels like any other app, you cannot tell anything about how it's implemented under the hood except that it's all built in web technology which is quite nice and you didn't have to go into the app store you didn't have to click install some button, it's really all happening in the background and progressively which is really cool another example is push notifications so this is one of the big, big use cases for a lot of native apps and one of the reasons e-commerce in particular why a lot of people want apps is because they can send these tickles to the user to say like hey we have a sale or some event has happened and we would like you to know about it you couldn't do that on the web but with service worker you can we have this push call back where your server sends a notification to the google cloud messaging server just like as you would say an android app and the cloud messaging server then tickles chrome on the device and chrome pushes up a notification just like any other notification on the device saying hey there's this thing that I want you to pay attention to and then when the user interacts with that notification you have another callback on the service worker which is on notification click which allows you to respond to that particular activity from the user, maybe that's to open your app maybe it's to do something else so I hope you're kind of getting the just an idea that like really what we're taking is we're taking a tab we're moving it outside of the tab we're giving it a life beyond that and it really becomes a standalone running application on your phone which is really quite cool and I think I've said this is really quite cool like 50 times now but it is really quite cool so long story short it's a worker it runs on a separate thread it has a completely independent life cycle the things that I've shown you here are not the full proposals and specifications for things like beacon notifications when you're in proximity of a beacon there's geo-fence type of discussions happening where you can declare a geo-fence and if you're in that area you get a notification callback on your service worker so there's a lot of really cool stuff that's happening here and service worker is really kind of that one enabling piece that the foundation that you need to get there so I think it's really good for you to start thinking about how I could leverage this even if I'm not leveraging push notifications or other things just to play with it and understand the kind of capabilities that you're going to get so with that, I'm out of time the slides are here there's a few typos in there that I'm going to fix but if there's any questions I'm happy to answer and since we are out of time we do have a break so I'm going to just hang around here and answer any other questions as well but maybe you can take a couple two, two yeah yeah we're restricted to HTTPS HTTPS origins, that's a requirement beyond that you have its scope to your origin and that's a security model there how would a user uninstall it like this thing, setting notifications on a bottom right yeah so that's a good question so in order to get notifications the user you do have to request permission but you don't have to request permissions up front like let's compare this to the typical app flow today you click the install button and it gives you a list of like I would like to access the internet and do the world and notifications and all the rest right with web technologies you request access for that particular feature when you need it so at some point in your app you'll say hey we have this cool new feature would you like us to notify you the user clicks on that we prompt the user say would you like to accept this and then there is a separate UI in the browser for invoking permissions for that sort of thing but that said a lot of things here are still under development under active development like cache one of the things we have not talked about is how much cache how much can I store and there are separate proposals and kind of APIs iterating through on durable storage and how much data you can store and all the rest at certain points there will be kind of pop-ups for the user that say hey this thing is trying to store a lot of data like it's trying to download a movie and I would like to do that so some of these details are still work in progress but we're getting there and if you have feedback then let us know yeah yeah so there is so this is a really good question about iframes so there is a concept of client requests and a client request that bypasses the service worker so if you have an iframe this is kind of the one interesting I'm not sure if it's a gotcha but it's part of the security aspect here when you have an iframe that bypasses your worker if there is a worker registered for that origin that owns whatever it is you fetching via the origin it would get invoked so let's say I have an iframe that is fetching from mysite.com and mysite has previously registered a service worker that request gets routed to that worker and it can do whatever it wants if there's no service worker it'll try to make the request directly to the network and fail if there is no connectivity so if you're building an offline app you really want to think about how many iframes do I have do I need them because I can't control them and this is part of the isolation because the promise of the iframe is basically not quite but it's an isolated context for security reasons and I'm one more it is right so the question is about client hints the XSAPCH stuff it is being adopted by the ITF HSP working group right now it is enabled by default in Chrome 46 I'm hoping that Firefox will start implementation soon and I've heard positive feedback from IE but I'm not sure where on their roadmap is today so the short answer is it's enabled in Chrome today hopefully coming to other browsers soon and with that I'm going to hang around here if you guys have any more questions, thank you