CSS-only chat
A truly monstrous async web chat using no JS whatsoever on the frontend.
This is …I mean …yes, but …it …I …
A truly monstrous async web chat using no JS whatsoever on the frontend.
This is …I mean …yes, but …it …I …
A great primer by Ire:
Web workers, service workers, and worklets are all scripts that run on a separate thread. So what are the differences between these three types of workers?
I was getting reports of some odd behaviour with the service worker on thesession.org, the Irish music website I run. Someone emailed me to say that they kept getting the offline page, even when their internet connection was perfectly fine and the site was up and running.
They didn’t mind answering my pestering follow-on questions to isolate the problem. They told me that they were using the Samsung Internet browser on Android. After a little searching, I found this message on a Github thread about using waitUntil
. It’s from someone who works on the Samsung Internet team:
Sadly, the asynchronos waitUntil() is not implemented yet in our browser. Yes, we will implement it but our release cycle is so far. So, for a long time, we might not resolve the issue.
A-ha! That explains the problem. See, here’s the pattern I was using:
Step 1 is the event listener:
// 1. When someone requests a file
addEventListener('fetch', fetchEvent => {
let request = fetchEvent.request;
fetchEvent.respondWith(
Steps 2, 3, and 4 are inside that respondWith
:
// 2. fetch that file from the network
fetch(request)
.then( responseFromFetch => {
// 3. create a copy of the file and cache it
let copy = responseFromFetch.clone();
caches.open(cacheName)
.then( cache => {
cache.put(request, copy);
})
// 4. return the contents.
return responseFromFetch;
})
Step 4 might well complete while step 3 is still running (remember, everything in a service worker script is asynchronous so even though I’ve written out the steps sequentially, you never know what order the steps will finish in). That’s why I’m wrapping that third step inside fetchEvent.waitUntil
:
// 2. fetch that file from the network
fetch(request)
.then( responseFromFetch => {
// 3. create a copy of the file and cache it
let copy = responseFromFetch.clone();
fetchEvent.waitUntil(
caches.open(cacheName)
.then( cache => {
cache.put(request, copy);
})
);
// 4. return the contents.
return responseFromFetch;
})
If a browser (like Samsung Internet) doesn’t understand the bit where I say fetchEvent.waitUntil
, then it will throw an error and execute the catch
clause. That’s where I have my fifth and final step: “try looking in the cache instead, but if that fails, show the offline page”:
.catch( fetchError => {
console.log(fetchError);
return caches.match(request)
.then( responseFromCache => {
return responseFromCache || caches.match('/offline');
});
})
Normally in this kind of situation, I’d use feature detection to check whether a browser understands a particular API method. But it’s a bit tricky to test for support for asynchronous waitUntil
. That’s okay. I can use a try
/catch
statement instead. Here’s what my revised code looks like:
fetch(request)
.then( responseFromFetch => {
let copy = responseFromFetch.clone();
try {
fetchEvent.waitUntil(
caches.open(cacheName)
.then( cache => {
cache.put(request, copy);
})
);
} catch (error) {
console.log(error);
}
return responseFromFetch;
})
Now I’ve managed to localise the error. If a browser doesn’t understand the bit where I say fetchEvent.waitUntil
, it will execute the code in the catch
clause, and then carry on as usual. (I realise it’s a bit confusing that there are two different kinds of catch
clauses going on here: on the outside there’s a .then()
/.catch()
combination; inside is a try{}
/catch{}
combination.)
At some point, when support for async waitUntil
statements is universal, this precautionary measure won’t be needed, but for now wrapping them inside try
doesn’t do any harm.
There are a few places in chapter five of Going Offline—the chapter about service worker strategies—where I show examples using async waitUntil
. There’s nothing wrong with the code in those examples, but if you want to play it safe (especially while Samsung Internet doesn’t support async waitUntil
), feel free to wrap those examples in try
/catch
statements. But I’m not going to make those changes part of the errata for the book. In this case, the issue isn’t with the code itself, but with browser support.
Here’s a great even-handed in-depth review of Going Offline:
If you’re interested in the “offline first” movement or want to learn more about Service Workers, Going Offline by Jeremy Keith is a really gentle and highly accessible introduction to the topic. At times, it even felt “too gentle”, with Keith taking a moment here and there to explain what a “variable” is and what “JSON” (JavaScript Object Notation) is. But, this just goes to show you the unassuming and welcoming mindset behind writing a book like this one.
Slides from a conference talk with a really clear explanation of how async
+ await
works with promises.
This article makes a good point about client-rendered pages:
Asynchronously loaded page elements shift click targets, resulting in a usability nightmare.
…but this has nothing, absolutely nothing to do with progressive web apps.
More fuel for the fire of evidence that far too many people think that progressive web apps and single page apps are one and the same.
Mariko has a real knack for explaining technical concepts in a very accessible way. This time it’s JavaScript promise
s.
Monica takes a look at the options out there for loading web fonts and settles on a smart asynchronous lazy-loading approach.
Scott shares the code that Filament Group are using to determine which style declarations are critical (and can be inlined) and which are non-critical (and can be loaded asynchronously). It makes quite a difference in perceived performance.
By the way, I really, really like the terminology of “critical” and “non-critical” CSS, rather than “above the fold” and “below the fold” CSS.
This looks like an interesting approach to web analytics: a JavaScript function pings the service every 10 seconds allowing for a near realtime overview.