The growth of technologies like local storage, and the exposure of certain device APIs — like the camera or geolocation — to the browser (or to a hybrid application) has had an interesting side effect on web developers: the growing need to check the connectivity state of the client. Users are becoming more accustomed to the ability to work seamlessly while disconnected and then synchronize later. In fact, as I write this I'm en route to the AngleBrackets conference, 30k feet in the air with no connectivity on my iPad using Daedalus (an awesome app, btw). But I fully plan to upload this post to my DropBox account when I land. The expectation for this kind of process to just work — maybe a novelty a few years ago — has overwhelmingly become the norm.
The reason(s) you are checking connectivity may vary per the type of application and intent:
Regardless of the reason or device - if you're working on web, mobile web or hybrid mobile applications, odds are very high that you will run into the need to check connectivity state on your current or next project. The question is....HOW should you go about it? Lets take a look at some of the APIs available to help you. (Warning: this isn't going to be an all-encompassing list, but a quick tour of some of the more common approaches.)
These events are fired when the browser switches to online or offline - starting on the body, and bubbling up to the document and the window. For a completely contrived example of using the window online
and offline
events:
// We simply subscribe to the offline or online event and pass a function (or function reference) // invoke our handler when the offline event occurs window.addEventListener("offline", whoopsWeAreOffline); // and when the online event occurs.... window.addEventListener("online", sweetBackOnLine);
The W3C spec description for navigator.onLine
is priceless:
Returns false if the user agent is definitely offline (disconnected from the network). Returns true if the user agent might be online…. Note: This attribute is inherently unreliable. A computer can be connected to a network without having Internet access. [emphasis added]
This does not inspire confidence. It's becoming apparent that a clear delineation between "The user said to work offline" and "Oops, we've lost our connectivity" hasn't quite landed with great browser API support yet. Nevertheless, for another contrived example, using the navigator.onLine
property:
if (navigator.onLine) { sweetWeAreKindaMaybeOnline(); } else { uhOhWeAreProbablyButNotDefinitelyOffline(); }
The "HTML5 rocks" website has a great post on using applicationCache events (as well as custom XHR response handling) to help indicate online/offline status. It's not sufficient on it's own, entirely – it still doesnt address the "User said to go offline" concern, and should ultimately be used in tandem with other approaches:
window.applicationCache.addEventListener("error", function(e) { weMightBeOffline(); }); window.applicationCache.addEventListener("downloading", function(e) { weAreProbablyOnline(); });
You might also be interested in reading Jake Archibald's aptly named post: "Application Cache is a Douchebag" (really, read it!).
If you're building a Cordova/Icenium/PhoneGap application, you can take advantage of the navigator.connection.type
property. Of course, this requires eager checking (it's not an event) - so it's best used in tandem with window online
and offline
(and possibly other) events.
if (navigator.connection.type === Connection.NONE) { weMightBeOffline(); } else { whoKnows(); // Could be wifi, cell*, ethernet or unknown }
If you're using a socket library such as socket.io, and you want the socket's connection state to play a part in your application's "online/offline" status, then you can hook into connect
and disconnect
events (assuming the library you chose provides them). Here's another contrived example, this time using socket.io:
socket.on('connect', function() { socketIsOnline(); }); socket.on('disconnect', function() { socketIsOffline(); });
Seriously, what more foolproof way to verify connectivity than to actually reach out and try to touch an endpoint? It definitely bypasses the weaknesses of other approaches that could give false positives (I'm looking at you, navigator.onLine). However, this method best demonstrates the need for a dedicated and structured way for your application to determine connectivity state. Think about it — are you going to make a heartbeat check before every request? I hope not! No —what we need is a way to trigger a heartbeat check when something might indicate (or even hint) that our connection might have dropped. The problem, though, is that most applications I've seen tend to only worry about connectivity right when they need to do something with the connection. This leads to if/else branching logic — testing for connectivity — being sprinkled all throughout the app. A better approach, in my opinion, is to separate the concern of connectivity so that it is handled by a dedicated component that can serve as the single source of truth for the app, and event out to other interested components as the state changes. There is an abstraction that is perfect for this, in my opinion: the finite state machine (FSM).
In part 2 of this series, we'll cover what an FSM is, look at some real world examples of them as well as how to create them using machina.js - a helper library for writing FSMs in JavaScript. Stay tuned for next week!