Application Cache is not gone, oh my! Or, is it?

Reports of Application Cache’s early demise are false. Application Cache (a.k.a Cache Manifest and AppCache) isn’t perfect, it can be very frustrating to get working and many people hate it with passion, but the fact is that the API will be around for the foreseeable future. I’ve been getting many questions, so this blog post is an attempt to shed some light on a confusing topic.

Mozilla says Application Cache is deprecated and unstable, WTF?

First, let’s review what Mozilla is saying about Application Cache since the majority of questions I get come from what they are saying. Mozilla has some fairly strong wording on their developer site, you can read all about it here. Or, if you don’t feel like following a link, here’s the official text from Mozilla Developer Network (MDN) website. I added the underlines to emphasize wording that’s tripping people up:

Deprecated. This feature has been removed from the Web standards. Though some browsers may still support it, it is in the process of being dropped. Do not use it in old or new projects. Pages or Web apps using it may break at any time.

Using the application caching feature described here is at this point highly discouraged; it’s in the process of being removed from the Web platform. Use Service Workers instead. In fact, as of Firefox 44, when AppCache is used to provide offline support for a page a warning message is now displayed in the console advising developers to use Service workers instead (bug 1204581).

Mozilla also references the Web Hypertext Application Technology Working Group’s (WHATWG) position on Application Cache. But, their wording is similar but definitely different in meaning from the WHATWG statement in their HTML Living Standard, Section 7.7. You may want to read this several times:

This feature is in the process of being removed from the Web platform. (This is a long process that takes many years.) Using any of the offline Web application features at this time is highly discouraged. Use service workers instead.

An oversimplified description of the WHATWG is it’s an organization that provides research and makes recommendations to the W3C – World Wide Web Consortium. It’s the W3C that finalizes recommendations and makes them into standards.

Also note: Application Cache is, for the moment, still officially part of the latest draft of the WHATWG HTML Living Standard document as shown here in Section 7.2.2 (it’s a big document, it’s best to just search for application cache).

 

What is the true state of Service Workers?

Reality is always nuanced when it comes to cross-browser web application development. Here’s a summary of facts for cross-browser developers to consider (as of February 1, 2016):

  • Service Workers are NOT supported on the following platforms, and you’ll need to use Application Cache if it suits your requirements and any Application Cache bugs don’t adversely affect your apps. You can verify these on caniuse.com.
    • Android Browsers at v4.4.4 and older (there are still a lot of phones out there using older browsers). Yes, a percentage of these users download Chrome. However, as of Feb 1, 2016, Android is reporting that v4.1.x thru v4.4 represents 60.8% of all phones in circulation.
    • Desktop Safari
    • iOS Safari
    • IE and Edge – don’t forget that a lot of offline field worker apps are built specifically for laptops.
  • The Service Worker specification is still a Working Draft according to the W3C. It’s not final according to the official standards bodies. Mozilla even lists Service Workers as “Experimental Technology”. You can view that yourself here. Here’s MDNs wording copied directly from their webpage:

This is an experimental technology 

Because this technology’s specification has not stabilized, check the compatibility table for the proper prefixes to use in various browsers. Also note that the syntax and behavior of an experimental technology is subject to change in future versions of browsers as the spec changes.

  • Service workers are more complex and require coding skills in comparison to Application Cache which requires only a configuration file and one line of HTML code. Here’s an example. It’s going to be a big step for long time Application Cache developers to wrap their heads around using Service Workers. It’s a very powerful API but it’s not going to be as easy as simply swapping out your Application Cache for offline capabilities built on Service Workers.

What to do, what to do?

My thoughts are MDNs statement leaves developers between a rock and a hard place, and holds the most water if the ONLY web browsers you need to support are browsers that have implemented all aspects of Service Workers that meet your requirements. You’ll also need to keep in mind that Service Workers are in beta so they can also can break or not work as expected, and there is a remote possibility the functionality could change.

When you combine MDN’s statement with the WHATWG statement and the WHATWG Living Standard document the picture becomes more clear. Here’s my interpretation: Application Cache is going to be around for a while longer. However, it would be a really good idea for you, as a cross-browser developer, to keep your eye on the progress of Service Workers and to consider using them in applications if/when it makes sense based on requirements and browser capabilities.

Don’t throw away an working/stable code built on Application Cache just yet.   If you are building apps on platforms that don’t support Service Workers then Application Cache may be your only viable alternative until you can upgrade to newer platforms or other browsers.

Additional References:

HTML5 Geolocation API: Getting the best single location

The Geolocation API is built into all modern mobile browsers and it lets you take either a quick, onetime snapshot, or you can get continuous location updates. Using the browser to get your approximate location is very, very cool, but it’s also fraught with many challenges. The vast majority of blog posts on this API talk about what it can do, this blog post focuses on how to best use it and understanding the data provided by the API.

To start things out, let’s take a quick look at a short list of some of the challenges when using the Geolocation API.

Challenge 1. You will not know where the location information is coming from. There’s no way to tell if it’s from the GPS, the cellular provider or the browser vendors location service. If you care about these things then the native Android SDK, for example, gives you a huge amount of control over what they call ‘location providers.’

Challenge 2. You cannot force the app to stay open. This means that the typical user has to keep tapping the app to keep it alive otherwise the screen will go to sleep and minimize your app.

Challenge 3. Speaking about minimizing apps, when the browser is minimized the geolocation capabilities stop working. If you have a requirement for the app to keep working in the background then you’ll need to go native.

Challenge 4. You’ll have very limited control over battery usage. Second only to the screen on your phone or tablet, the current generation of GPS chips are major energy hogs and can suck down your battery very quickly. Since the Geolocation API gives you very little control over how it works you cannot build much efficiency into your apps.

Challenge 5. Most smartphones and tablets use a consumer-grade GPS chip and antenna, and that limits the potential accuracy and precision. On average, the best possible accuracy is typically between 3 and 10 meters, or 10 – 33 feet. This is based on my own extensive experience building GPS-based mobile apps and working with many customers who are also using mobile apps. Under the most ideal scenario, the device will be kept stationary in one location until the desired accuracy number is achieved.

What’s it good for? Okay, you may be wondering what is browser-based geolocation good for? It’s perfect for very simple use cases that don’t require much accuracy. If you need to map manhole covers, or parking spaces, or any other physical things that are close together you’ll need a GPS device with professional-level capabilities.

Here are a few generic examples that I think are ideal for HTML5 Geolocation:

  • Simply getting your approximate location in latitude/longitude and converting it to a physical address.
  • Finding an approximate starting location for searching nearby places or things in a database or for getting one-time driving directions.
  • Determining which zip code, city or State you are in to enable specific features in the app.
  • Getting the approximate location of a decently sized geological feature such as a park, a building, a pond, a parking lot, a driveway, a group of trees, an intersection, etc.

What’s the best way to get a single location? The best way to get a single location is to not use getCurrentPosition() but to use watchPosition() and analyze the data for a minimum set of acceptable values.

Why? Because getCurrentPosition() simply forces the browser to barf up the best available raw, location snapshot right now. It literally forces a location out of the phone. Accuracy values can be wildly inaccurate, especially if the GPS hasn’t warmed up, or if you aren’t near a WiFi with your WiFi turned on, or if your cellular provider can’t get a good triangulation fix on your phone, or it returns a cached value from a different location altogether. There are many, many “what ifs?”

So, I recommend using watchPosition() and firing it off and letting it run until the return values meet some minimum criteria that you set. You need to know that while this is happening the location values returned may cover a fairly wide geographic area…remember our best accuracy values are 10 – 30 meters. Here’s a real-world example of Geolocation API location values that I captured over a 5 minute period while standing stationary in front of a building.

5 minute snapshot

What steps do you recommend? Here are five basic steps to help guide you towards one approach for getting the best location. This is a very simplistic approach and may not be appropriate for all use cases, but I think it’s adequate to demonstrate the basic concepts for working towards determining the best possible location.

Step 1. Immediately reject any values that have accuracy above a certain threshold that you determine. For example, let’s say we’ll reject any values with an accuracy reading greater than 50 meters.

Step 2. Create three arrays, one for accuracy, latitude and longitude. If the accuracy is below your threshold, or in this case < 50 meters, then push the values to the appropriate arrays. You will also need to set a maximize size for the array and create a simple algorithm for adding new values and removing old ones.

The array length could be 10, 20 or even 100 or more entries. Just keep in mind that the longer the array, the longer it will take to fill up and the longer the user will have to wait for the end result.

Step 3. Start calculating the average values for accuracy, latitude and longitude.

Step 4. Start calculating the standard deviation for accuracy, latitude and longitude.

Step 5. If your arrays fill up to the desired length and the average accuracy meets your best-possible criteria, and the standard deviation is acceptable then you can take the average latitude, longitude values as your approximate location.

For an example of this simple algorithm at work visit the following URL on your phone and step outside to get a clear view of the sky: https://esri.github.io/html5-geolocation-tool-js/field-location-template.html. [Updated link: Oct. 27, 2015]

Offline JavaScript Part 3 – Intermittent Offline

This is Part 3 of my offline JavaScript series and it covers intermittently offline web apps. The vast majority of web apps are built on the false assumption that the internet will always be available. Yes, the internet is available the vast majority of the time, and most of us rarely encounter issues. However when, not if but when, the internet fails most web apps simply crash and burn in fairly spectacular fashion. I suggest a different approach that there are many, many common use cases that can benefit from offline capabilities in both consumer and professional apps.

As discussed in Part 1, intermittently offline web apps are designed to gracefully handle the occasional, temporary internet connection hiccup. The goals of an intermittent offline app are to make the offline capabilities are lightweight, invisible to the user, and allow the user to seamless pass thru a temporary loss of data connectivity.

The good news, as discussed in Part 2, is you can use a variety of libraries and APIs to solve many of the challenges related to partial offline including detecting whether or not you have an internet connection, and handling of http requests while offline.

How do I decide if I need intermittent offline capabilities?

If you answer ‘yes’ to the following question then you need to consider adding offline capabilities:

Does the app have any critical functionality that could fail if the internet temporarily goes down?

Critical functionality means functionality that’s important to your core business. And to be realistic I’m not talking about building fully armored applications that take every possible contingency into account. That’s just not feasible for the vast majority of non-military-grade applications. Some of the most common use cases are filling in forms and requesting data. And, temporary interruptions can be vary anywhere from a few seconds to a few minutes or longer, and they can happen once or multiple times.

If your application can’t handle this and it needs to then making changes to allow it to be offline can make a big difference to the user. It’s almost as if web development should have it’s own version of “Do no harm” or something like “we can do our best to make users lives easier.” You might be surprised that some very simple and common use cases can benefit from being offline enabled such as filling in form data, or reading an online article.

Filling in form data. This has probably happened to everyone who uses the internet and it applies to both retail/consumer and commercial applications. You spend a while filling out a detailed web form only to have the submit fail and destroy all your hard work because of a temporary interruption in the internet connection or something simply went wrong between the app and the web server.

If our form data was offline-enabled we could store the form data in LocalStorage before attempting to send the data to the server. We could also temporarily prevent the web form from submitting and notify the user there is no internet connection.

Reading an online article. In this scenario you are reading an article while waiting for a train.  Once you get on the train you know the internet will be marginal. You accidentally click on navigation link while scrolling down and the new page fails to load. This effectively ruins your browsing experience because the new page failed to load and you can’t go back to the previous page because it wasn’t cached..

There are a number of different ways to protect this type of application. The easiest way is to block any page load requests until the internet is restored. You can also take advantage of the built-in browser cache to store HTML, CSS, images and JavaScript.

Show me an example workflow?

The most basic workflow takes into consideration the following questions. How these questions get answered depends on your requirements.

  • Do you allow users to restart apps while offline?
  • Do you simply block all HTTP requests and lock down the app?
  • Do you queue HTTP requests and their data?
  • Do you pre-cache certain data?
  • How will you detect if the app is online or offline?

Here is an example coding pattern for the most basic intermittent offline workflow:

What about Offline/Online detection?

If you have no control over what browsers your customers choose, then my recommendation is to use a pre-built library such as Offline.js to check if the internet connection is up or down. It’s not perfect but it’s the best choice out there as of the writing of this post.

Don’t only rely on the window.navigator.online property. It has too many inconsistencies and it is only marginally reliable if the general public is using your app.

What about caching?

There are several built-in browser caching mechanisms that can help your app get past the occasionally internet hiccup. When your app goes offline, you’ll have to rely on local, in-browser resources to keep things going:

  • Browser Caching
  • LocalStorage
  • IndexedDB

As mentioned above, browser caching can be a very efficient way to store HTML, JavaScript, images and CSS. Depending on how you set up your web server, this caching takes place automatically in the users browser and can represent a huge performance gain in eliminating HTTP round trips. I’m not going to talk much about this because there are a ton of great online resources already out there.

Using LocalStorage involves writing JavaScript code if you want to temporarily store HTTP requests. It’s limited to String-based data, so if you are using Objects or binary data you’ll have to serialize the data when you write it to LocalStorage and deserialize when you read it out. LocalStorage also almost always has a limit in terms of how much storage is available. 5MB is the commonly accepted limit.

IndexedDB, on the other hand, stores a wide variety of data types and can store significantly more than 5MB. While in theory the amount of storage space available to IndexedDB is unlimited, practical application of it on a mobile device limits you to around 50MB – 100MB. Your mileage may vary depending on available device memory, the current memory footprint of the browser and the phone’s operating system.

IndexedDB can work natively with types String, Object, Array, Blob, ArrayBuffer, Uint8Array and File. This offers a huge pre- and post-processing savings if you simply are able to pass data directly into IndexedDB.

There are also a number of abstraction libraries that wrap LocalStorage and IndexedDB such as Mozilla’s localForage. These types of libraries are great if you have requirements to store 5MBs of data or less. If your app is running a browser that doesn’t support IndexedDB or WebSQL (e.g. Safari), and you need more than 5MBs of space then you’ll have problems. One potential advantage of some of these libraries is that some of them provide their own internal algorithms for serializing and deserializing data. If working directly with algorithms isn’t your thing, then a library like this can be a huge benefit.

Can you show me some code?

Yes! Here is a very simple example of how to implement basic offline detection into your apps. It’s easiest to try it in Firefox since you can quickly toggle it online/offline using the File > Work Offline option.

The code is available at: https://jsfiddle.net/agup/1yxj5mzp/. You’ll notice two things when you go offline. First is that jsfiddle, itself, will detect you are offline in addition to the web app code. When you go to click the Get Data button while offline, the code sample should detect you are offline and fire off a JavaScript alert.

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Simple Offline Demo</title>
</head>
<body>
<div id="status">Status is:</div>
<button onclick="getData()">Get Data</button>
<!-- This is our Offline detection library -->
<script src="https://github.hubspot.com/offline/offline.min.js"></script>

<script>

    // Set our options for the Offline detection library
    Offline.options = {
        checkOnLoad: true,
        checks: {
            image: {
                url: function() {
                    return 'https://esri.github.io/offline-editor-js/tiny-image.png?_='
                        + (Math.floor(Math.random() * 1000000000));
                }
            },
            active: 'image'
        }
    }

    Offline.on('up', internetUp);
    Offline.on('down',internetDown);

    var statusDiv = document.getElementById("status");
    statusDiv.innerHTML = "Status is: " + Offline.state;

    function getData() {

        // See if internet is up or down
        Offline.check();

        switch (Offline.state) {
            case "up":
                // If the internet is up go ahead and retrieve data.
                getFeed(function(success,response){
                    if(success){
                        alert(response);
                    }
                })
                break;
            case "down":
                alert("DOWN");
                break;
        }
    }

    function getFeed(callback) {
        var req = new XMLHttpRequest();
        req.open("GET",
                "https://tmservices1.esri.com/arcgis/rest/services/LiveFeeds/Earthquakes/MapServer?f=pjson");
        req.onload = function() {
            if (req.status === 200 && req.responseText !== "") {
                callback(true,req.responseText);
            } else {
                console.log("Attempt to retrieve feed failed.");
                callback(false,null);
            }
        };

        req.send(null);
    }

    function internetUp(){
        console.log("Internet is up.");
        statusDiv.innerHTML = "Status is: up";
    }

    function internetDown(){
        console.log("Internet is down.");
        statusDiv.innerHTML = "Status is: down";
    }
</script>
</body>
</html>

Are there any examples of real-life offline apps or libraries?

The github repository offline-editor-js is a full-fledged set of libraries for taking maps and mapping data offline and it’s being used in commercial mapping applications around the world. It includes a variety of sample applications that demonstrate how applications can work in either intermittently or fully offline mode.

Wrap-up

Hopefully you have seen that common use cases can significantly benefit from having basic offline capabilities. Modern browsers have advanced to the point where it’s fairly easy to build web apps that can survive intermittent interruptions in the internet. Taking advantage of these capabilities can offer a huge benefit to your end users.

Resources

Optimizing content efficiency – HTTP caching
Offline-editor-js – Offline mapping library