For years, if we wanted to store local data we would look to using HTTP cookies—a convenient way to persist small amounts of data on a user's machine. And we do mean small: cookies are limited to about 4KB apiece. Also, the cookie is passed along with every request and response even if it isn't used, making for heavy HTTP messaging.

Enter the web storage APIs, a way for you to store key/value paired string values on a user's machine. Local storage provides much more space—modern browsers support a minimum of 5MB, much more than the 4KB for cookies.

When using web storage, we can implement either localStorage or sessionStorage from the Storage object. Let's work through how to accomplish this.

Checking web storage compatibility

Although most browsers support web storage, you still should be a good developer and verify that a user isn't using an unusually old browser like IE6:

function isWebStorageSupported() {  
 return 'localStorage' in window;
}

When to use localStorage or sessionStorage

The localStorage and sessionStorage APIs are nearly identical with one key exception: persistence.

The sessionStorage object is only available for the duration of the browser session, and is deleted automatically when the window is closed. However, it does stick around for page reloads.

Meanwhile, localStorage is persisted until it is explicitly by the site or the user. All changes made to localStorage are available for all current and future visits to the site.

Whatever the case, both localStorage and sessionStorage work well when working with non-sensitive data needed within an application since data stored in localStorage and sessionStorage can easily be read or updated from a user's browser.

Web storage API methods and properties

The following is a list of methods and properties available on global Storage object's localStorage and sessionStorage variables.

  • key(index) - finds a key at a given index. As with finding indexes in other code you write, you should check the length before finding an index to avoid any null or out-of-range exceptions.
  • getItem(key) - retrieve a value by using the associated key.
  • setItem(key, value) - stores a value by using the associated key. Whether you are setting a new value or updating an existing value, the syntax is the same.
  • removeItem(key) - removes a value from local storage.
  • clear() - removes all items from storage.
  • length - a read-only property that gets the number of entries being stored.

Can I store objects?

While you can only have string values in web storage, you can store arrays or even JavaScript objects using the JSON notation and the available utility methods, like in the following example.

var player = { firstName: 'Kris', lastName: 'Bryant' };  
localStorage.setItem('kris', JSON.stringify(player));  

You can then use the parse() method to deserialize the kris object.

var player = JSON.parse(localStorage.getItem('kris'));  

Keeping web storage synchronized

How do you keep everything in sync when a user has multiple tabs or browser instances of your site open concurrently? To solve this problem, the web storage APIs have a storage event that is raised whenever an entry is updated (add/update/removed). Subscribing to this event can provide notifications when something has changed. This works for both localStorage and sessionStorage.

Subscribers receive a StorageEvent object that contains data about what changed. The following properties are accessible from the StorageEvent object. The storage event cannot be canceled from a callback. The event is merely a notification mechanism: it informs subscribers when a change happens.

  • key - gets the key. The key will be null if the event was triggered by clear()
  • oldValue - gets the initial value if the entry was updated or removed. Again, the value will be null if an old value did not previously exist, or if clear() is invoked.
  • newValue - gets the new value for new and updated entries. The value is null if the event was triggered by the removeItem() or clear() methods.
  • url - gets the URL of the page on the storage action
  • storageArea - gets a reference to either the localStorage or sessionStorage object

To begin listening for event notifications, you can add an event handler to the storage event as follows.

function respondToEvent(event) {  
 alert(event.newValue);
}

window.addEventListener('storage', respondToChange, false);  

To trigger this event, perform an operation like the following in a new tab from the same site.

localStorage.setItem('player', 'Kris');  

The fine print

While web storage offers many benefits over cookies, it is not the end-all, be-all solution, and comes with serious drawbacks as others have noted.

  • Web storage is synchronous - because web storage runs synchronously, it can block the DOM from rendering while I/O is occurring.
  • No indexing or transactional features - web storage does not have indexing, which may incur performance bottlenecks on large data queries. If a user is modifying the same storage data in multiple browser tabs, one tab could potentially overwrite the value in another.
  • Web storage does I/O on your hard drive - because web storage writes to your hard drive, it can be an expensive operation depending on what your system is currently doing (virus scanning, indexing data, etc.) While you can store a lot more data in local storage, you'll need to be cognizant of performance.
  • Persistence - if a user no longer uses a site and storage is not explicitly deleted, storage is still loaded when you start the browser session
  • First request memory loading - because browsers load data into memory, it could use a lot of memory if many tabs are utilizing web storage mechanisms.

Web storage does offer you a simple, direct way to store user data, with caveats that it can degrade performance if you do not use it wisely thanks to its synchronous, I/O nature. Much like anything else you code, understand its utility and its nuances before using it, and don't be greedy. It very well can bite you in the rear end if you expect too much.


Building location-aware applications is a snap with the HTML5 Geolocation APIs. These APIs allows you to retrieve a user’s location – with the user’s permission – as a one-time request or over a period of time. This post will walk you through how to implement the Geolocation API.

Checking for support

When implementing the Geolocation APIs, the first thing you’ll want to do is see if geolocation is supported by a user’s browser. (You’ll notice that the geolocation functionality is supported by virtually all browsers, but you know what they say about assuming.) You can check by writing code that uses the in operator; this returns true if the geolocation property exists in the window’s navigator object.

function supportsGeolocation() {  
    return 'geolocation' in navigator;
}

Now that you can use the Geolocation API, you can use the position.coords property to retrieve some of the following values:

  • The latitude and longitude attributes are geographic coordinates specified in decimal degrees.
  • The altitude attribute denotes the height of the position, specified in meters. If the implementation cannot provide altitude information, the value of this attribute must be null.
  • The accuracy attribute denotes the accuracy level of the latitude and longitude coordinates. It is specified in meters and must be supported by all implementations.
  • The altitudeAccuracy attribute is specified in meters. If the implementation cannot provide altitude information, the value of this attribute must be null.
  • The heading attribute denotes the direction of travel of the hosting device and is specified in degrees, where 0° ≤ heading < 360°, counting clockwise relative to the true north. If the implementation cannot provide heading information, the value of this attribute must be null. If the
    hosting device is stationary, then the value of the heading attribute must be NaN.
  • The speed attribute denotes the magnitude of the horizontal component of the hosting device’s current velocity and is specified in meters per second. If the implementation cannot provide speed information, the value of this attribute must be null.

From here, you can decide if you want to get a user’s current location (one-time event), or watch a current position (specified time).

Getting current location

There are many scenarios where you just want to get a user’s location once – like, where is a user’s closest movie theater or grocery store? If this is what you’re after, then you can call the getCurrentLocation method from the navigator.geolocation object.

This method sends an async request to detect the user’s position. When the position is determined, a callback function is executed. You can optionally provide a second callback function to be executed if an error occurs and also a third parameter as an options object. In the options object, you can set the following attributes:

  • enableHighAccuracy – get the best possible result, even if it takes longer (default is false)
  • timeout – timeout, in milliseconds, that the browser will wait for a response (the default is -1, meaning there is no timeout)
  • maximumAge – specifies that a cached location is acceptable, so long as it isn’t longer than the milliseconds that you specify (the default is 0, meaning a cached location is not used)

In the following example, I’ll build a simple page that asks a user to click a button that will execute a function to find a user’s location. The information will be displayed in the location div.

<html>  
    <head>
        <script src="js/current-location.js"></script>
    </head>
    <body>
        <p><button onclick="findMe()">Show my location</button></p>
        <div id="location"></div>
    </body>
</html>  

The following example retrieves the latitude, longitude, and accuracy of the current user, given that they give permission to access their location. After getting this information, we’ll display a Google Maps image of their location, easily accessible by using the Google Maps API, which takes latitude and longitude as parameters.

function findMe() {  
  var output = document.getElementById("location");

  function success(position) {
    var latitude  = position.coords.latitude;
    var longitude = position.coords.longitude;
    var accuracy = position.coords.accuracy;

    output.innerHTML = '<ul> \
                        <li>Latitude: ' + latitude + ' degrees</li> \
                        <li>Longitude: ' + longitude + ' degrees</li> \
                        <li>Accuracy: ' + accuracy + 'm</li> \
                        </ul>';

    var img = new Image();
    img.src = "https://maps.googleapis.com/maps/api/staticmap?center=" + latitude + "," + longitude + "&zoom=13&size=300x300&sensor=false";
    output.appendChild(img);
  };

  function error() {
    output.innerHTML = "Unable to retrieve your location!";
  };

  output.innerHTML = "Getting location ...";

  var options = {
      enableHighAccuracy: true,
      timeout: 3000,
      maximumAge: 20000
  };

  navigator.geolocation.getCurrentPosition(success, error, options);
}

Monitoring current location

If you see a user’s position changing frequently, like with turn-by-turn directions, you can set up a callback function that you call with the updated position information. You can accomplish this by using the watchPosition function. This function
has the same parameters as getCurrentPosition.

The watchPosition method returns an ID that can be used to identify who or what is watching the position. Then, when you wish to stop watching a user’s location, you can use the clearWatch method which takes the ID as a parameter.

In this case, we have another simple page that has buttons to start and stop watching a user’s position. The position information will display in the message div.

<html>  
    <head>
        <script src="js/jquery-3.1.0.min.js"></script>
        <script src="js/watch-position.js"></script>
    </head>
    <body>
        <div id="message"></div>
        <button id="startLocation">Start</button>
        <button id="stopLocation">Stop</button>
    </body>
</html>  

In the JavaScript file, we’ll start by initializing a watchId, using jQuery to initiate click events (more on that in a second), checking to see if the API is supported, and then writing a utility method that will show the information in the message div.

var watchId = 0;

$(document).ready(function() {
    $('#startLocation').on('click', getLocation);
    $('#stopLocation').on('click', endWatch);
})

function supportsGeolocation() {  
    return 'geolocation' in navigator;
}

function showMessage(message) {  
    $('#message').html(message);
}

And now, here’s where the magic happens: if a user’s browser supports geolocation, we call watchPosition, which in this case take a success callback, an optional error callback, and an optional options parameter.

function getLocation() {  
    if (supportsGeolocation()) {
        var options = {
            enableHighAccuracy: true
        };
        watchId = navigator.geolocation.watchPosition(showPosition, showError, options);
    }
    else {
        showMessage("Geolocation is not supported by this browser.");
    }
}

function showPosition(position) {  
    var datetime = new Date(position.timestamp).toLocaleString();
    showMessage("Latitude: " + position.coords.latitude + "<br />"
              + "Longitude: " + position.coords.longitude + "<br />"
              + "Timestamp: " + datetime);
}

function showError(error) {  
    switch (error.code) {
        case error.PERMISSION_DENIED:
            showMessge("User denied Geolocation access request.");
            break;
        case error.POSITION_UNAVAILABLE:
            showMessage("Location information unavailable.");
            break;
        case error.TIMEOUT:
            showMessage("Get user location request timed out.");
            break;
        case error.UNKNOWN_ERROR:
            showMessage("An unknown error occurred.");
            break;
    }
}

Finally, when the user clicks the Stop button, the clearWatch method is called and the browser stops tracking the user’s location.

function endWatch() {  
    if (watchId != 0) {
        navigator.geolocation.clearWatch(watchId);
        watchId = 0;
        showMessage("Monitoring complete.");
    }
}


The Application Cache (AppCache) API allows offline access to your application by providing the following benefits:

  • Performance - Specified site resources come right from disk, avoiding any network trips
  • Availability - Users can navigate to your site when they are offline
  • Resilience - If a server breaks or something bombs and your site is inaccessible online, users can still use your offline site.

In this post, we’ll explore how to implement AppCache and investigate its benefits and many drawbacks. If you would like to play along at home, feel free to reference an AppCache repo I created on GitHub.

Creating a manifest file

First, you’ll need to create a manifest file, a static text file that tells the browser which assets to cache for offline availability. A manifest can have three different sections (the order and frequency of these sections do not matter):

  • Cache - This default section lists the site assets that will be cached after an initial download.
  • Network - Files listed here can come from the network if they aren’t cached. Otherwise, the network isn’t used even if the user is online.
  • Fallback - A section, which is optional, that specifies pages to use if a resource is not available. The first URI is the resource, and the second is what is used if the network request fails or errors.

Keep in mind the following “gotchas” with the manifest: if the manifest file cannot be found, the cache is deleted. Also, if the manifest or a resource specified in the manifest cannot be found and downloaded, the entire offline caching process fails and the browser will keep using the old application cache.

So, when will the browser use a new cache? This occurs when a user clears their cache, a manifest file is modified, or programmatically (we’ll get to that later).

Pay special attention to the second item. A common misconception is that when any resources listed within the manifest change, they will be re-cached. That is wrong. The manifest file itself needs to change. To facilitate this, it is a common practice to leave a timestamp comment at the top of the file that you can update whenever the manifest changes, such as in my example below.

# v5 2016-08-15
index.html  
css/main.css  
scripts/script.js  
images/hanna.jpg  
images/emma.jpg

NETWORK:  
*

FALLBACK:  
offline.html  

Referencing the manifest file

Now that you’ve created the manifest file, you then need to reference it in your web page(s). To do this, you’ll need to append the manifest attribute to the opening tag of any page you want cached:

<html manifest="manifest.appcache">  
...
</html>  

This bears repeating: the attribute must be included on every page that you want cached. The browser will not cache a page if the manifest attribute is not included on the specific page.

Using the AppCache APIs

Now that you have created the manifest file and decided which pages you want to be cached, you can now talk to the AppCache programmatically from the global JavaScript window.applicationCache object. From this object, you can call the following methods:

  • abort - kills the cache download process
  • addEventListener - registers an event handler for a specific event type
  • dispatchEvent - sends an event to a current element
  • removeEventListener - removes a handler previously registered by addEventListener
  • swapCache - swaps an old cache for a new cache
  • update - triggers an update of the existing cache only if updates are available

From the MDN documentation on AppCache, here’s how you would see if your application has an updated manifest file.

function onUpdateReady() {  
  console.log('I found a new version!');
}

window.applicationCache.addEventListener('updateready', onUpdateReady);

if (window.applicationCache.status === window.applicationCache.UPDATEREADY) {  
  onUpdateReady();
}

Note, as specified in the MDN documentation, that “…since a cache manifest file may have been updated before a script attaches event listeners to test for updates, scripts should always test applicationCache.status.”

The fine print

In Application Cache is a Douchebag, Jake Archibald brilliantly lays out the many limitations of the AppCache API. You should read that piece for the full details, but here are a few gotchas that I haven’t mentioned yet:

  • Files come from the cache if you’re online – you’ll first get a version of the site from your cache. After rendering, the browser then finds updates to the manifest. As noted in the article, it means the browser doesn’t have to wait for timing out connections, but it’s somewhat annoying.
  • Non-cached resources don’t load on a cached page – if you cache, for example, a web page but not an image on it, the image will not display on the page even when you are online. Really. You would get around this by adding the * to the Network section in your manifest. (However, these connections will fail anyway if you are offline.)
  • You can’t access a cached file by its parameters – accessing index.html by parameters such as index.html?parameter=value will not retrieve the cached page. It will fetch the page over the network.

As you can imagine, AppCache’s limitations have spurned a “let’s not use AppCache” movement across the Web. It has been removed from the Web standards in favor of service workers. When describing service workers, the MDN documentation summed up AppCache’s rise and fall nicely:

The previous attempt — AppCache — seemed to be a good idea because it allowed you to specify assets to cache really easily. However, it made many assumptions about what you were trying to do and then broke horribly when your app didn’t follow those assumptions exactly.

So to answer my initial question, it is not worth it; don’t use AppCache. Unless you are completely aware of the limitations and able to live with them, AppCache’s drawbacks outweigh its benefits. The community has spoken, and using local storage or service workers is the preferred approach.