Going Offline: Designing An Ideal Offline Experience With Service Workers By Jeremy Keith
For the last few years, I've been enamored with the idea of "offline first" development. And, I've even spent a good amount of time digging into PouchDB - a client-side database, based on the CouchDB API, that is positioned perfectly for an offline first experience. In my mind, Service Workers were always going to be "the thing" that tied all of my research and development together. But, unfortunately, I never made it that far.
Now, with the light that "Going Offline" has shed on the topic, I'm feeling reinvigorated. But, also, much more educated. Up until reading this book, I had an immature mental model in which "offline first", "Progressive Web Apps (PWAs)", and "Service Workers", were all one in the same. I now see that the use of Service Workers is much more nuanced; and, that it applies to a broader range of projects, not just Single Page Applications (SPAs) and pseudo-native experiences.
In fact, Keith's exploration of an Offline / Fallback page for "normal websites" is probably going to be the first type of Service Worker interaction that I experiment with. I really enjoyed how he used the Fallback page concept to showcase a few facets of this new technology:
- How the Service Worker API can augment - or progressively enhance - a non-"app" context.
- How the Cache API can be used both inside and outside of the Service Worker.
- How other technologies like the LocalStorage API can be used in conjunction with the Cache API in order to provide an even richer user experience.
- How the Cache API can be used to create "Save for Later" functionality.
If I had one criticism of the book, it's that Keith kind of glossed over the .waitUntil() method. As he iterates through his examples, they all grow to include .waitUntil() calls on each Service Worker event object. When this is first encountered, he does explain that the .waitUntil() method is used to hold the event open:
There's a chance that the service worker might "power down" once the user has received the response. If that happens, the copy might never end up in the cache.... you can make sure the copy gets cached by invoking the waitUntil method on the fetchEvent. You're telling the fetchEvent to stay active until the caching code completes, even if a respnose has already been received. (Page 84)
Unfortunately - or perhaps more just "atypically" - this turns out to be the case with Service Workers. When I was done reading the Going Offline book, I went online (see what I did there?) and did a little research on the .waitUntil() method. According to the Service Worker specification, the browser "may" (or, may not) terminate a service worker at any time if:
- It has no event to handle.
- It detects abnormal behavior (such as an infinite loop).
- Its processing time exceeds the imposed time limit.
So, it appears that unlike a Node.js process, "doing work" isn't enough to keep a Service Worker running. As such, you have to use the .waitUntil() method on the Service Worker event objects in order to hold the events open while interacting with the Cache API or the fetch API.
One interesting caveat of this, as pointed out by Chris Love on YouTube, is that a long running "activate" event will actually buffer concurrent fetch events. This is done in order to ensure that the Service Worker is in a consistent state whenever any of the events fire. But, this also means that if your "activate" event takes a while, the user won't be able to make calls for remote resources until the activate event completes.
The .waitUntil() method aside, I felt like Keith went appropriately deep into the other APIs relating to the offline landscape. At no point does the book read like documentation - he never list out all possible methods and arguments. But, he is pragmatic and does explain what all of the methods do in relation to the outcomes he's trying to achieve in the code examples. This keeps the flow of the book feeling very natural and incremental; and, at no point overwhelming.
Sounds great. I've played with SWs before and found it to be a powerful API. Don't think I ever came across waitUntil(). Glad you called that out.
FYI: typo "but, does who does have"
What kinds of stuff have you used Service Workers for? Has it been more "App" kind of things? Or, have you used this more for "Website" kind of things (if the differentiation there makes sense).
I'm excited to get my toes wet.
In my case, we had an online-first back-office app that needed to work offline. It was used to adjust inventory levels and assumed (inaccurately) that our clients would always have access to wifi. So I started experimenting with service workers to solve the offline problem, caching inventory updates locally to submit to our ColdFusion backend once reconnected. I got it working in the context I was testing, but didn't have the resources to test the entire app, so we unfortunately lacked the confidence needed to launch. And they moved me onto other things before I could truly finish it up.
That actually sounds really cool! A while back, I played around with PouchDB, because of its ability to sync with a live database. But, in the case that I was looking at, each user would have their own live database to sync to. I am not sure that such a technology would even make sense when multiple people need to sync to a single database (not even sure how that would work). So, that's pretty cool that you essentially buffered API calls (or however it was done). Sounds exciting! Sorry you didn't get a chance to finish it.