13

I'm testing HTML5 offline application. To do that, I'm stopping my local web server (IIS) and open application. It's loaded fine, but it failed as soon as it request server side API method.

I want to prevent that and instead of $.get('/api/method') read data from my local storage. But I can found any facility to understand my application is offline.

if (/* online */) {
  // fire ajax
} else {
  // ask localstorage
}

I tried to use navigation.onLine but it seems to be always true (at least I can see that in Chrome).

Do you have any suggestions?

EDIT: taking into account current answers. Application is clearly understand that it's offline, since it takes resources according to cache.manifest. It's ridiculous to me, that client need to do any kind of tricks and pings. I assume there should be a easy way to check current mode.

Alexander Beletsky
  • 18,109
  • 9
  • 57
  • 84
  • try to look at upshot.js sources. they have implemented this behaviour – mironych Mar 20 '12 at 12:05
  • 2
    There's no easy way to check because there's no easy way to know what constitutes 'online'. The network interface could be up, the device/PC could be on a network, but if that network has no connection to the internet then are you online or offline? That would depend on whether the application is on the internet or the intranet. What if you have internet access is available but your app is blocked by firewall rules, is your app online or offline? The easiest way to check *is* some sort of ping. – robertc Mar 20 '12 at 12:11
  • @robertc your comment makes a lot of sense to me, thanks! – Alexander Beletsky Mar 20 '12 at 12:13
  • @sound I heard about upshot.js - but I'm not sure, to pick up "whole" lib just to one check, thought it can be easier; – Alexander Beletsky Mar 20 '12 at 12:14

6 Answers6

13

One easy way to check is to add a fallback section in your manifest like this:

FALLBACK
/online.js /offline.js

Then in online.js you set a global variable to true, in offline.js you set it to false and you just request online.js by Ajax whenever you plan to do some networking and do whatever processing you need conditionally in the callback. In the meantime, maintain all your app data client side.

An alternative approach is a blocking polyfill for navigator.onLine as suggested by Remy Sharp.

robertc
  • 69,665
  • 18
  • 184
  • 170
3

online state could be also checked doing an ajax HEAD request with a timeout and when timeout is reached (or the call returns an error status) you can assume you're working offline (no network capabitlities) and you have to use localstorage instead

In fact, for the sake of state consistency, localstorage should be used as a fallback not only when you're offline, but also when you're online and the specific ajax resource is not temporarily available (e.g. site overload). Of course you will need to make a continuos polling to that resource with regular (or incremental) timeout until it becomes available again.

Fabrizio Calderan loves trees
  • 109,094
  • 24
  • 154
  • 160
1

I was needing the same functionality and after much searching found this function:

http://louisremi.com/2011/04/22/navigator-online-alternative-serverreachable/

Here is the code from the article, just in case the link goes down:

function serverReachable() {
  // IE vs. standard XHR creation
  var x = new ( window.ActiveXObject || XMLHttpRequest )( "Microsoft.XMLHTTP" ),
     s;
  x.open(
      // requesting the headers is faster, and just enough
      "HEAD",
      // append a random string to the current hostname,
      // to make sure we're not hitting the cache
      window.location.href.split("?")[0] + "?" + Math.random(),
      // make a synchronous request
      false
  );
  try {
      x.send();
      s = x.status;
      // Make sure the server is reachable
      return ( s >= 200 && s < 300 || s === 304 );
  } 
  // catch network & other problems
  catch (e) {
     return false;
  }
}

Note that the code above includes a fix by Scott Jehl for working with localhost which is posted lower down in the comments. And here is a link to a jQuery version of the same function:

https://gist.github.com/scottjehl/947084

And the code from that link:

function serverReachable() {
    var s = $.ajax({
           type: "HEAD",
           url: window.location.href.split("?")[0] + "?" + Math.random(),
           async: false
       }).status;
    return s >= 200 && s < 300 || s === 304;
};

I have found this technique to be really effective. Because the request is only for header information it is reasonably fast and it works across all browsers. Great success! :)

I hope other find this as helpful as I did. :)

BruceHill
  • 6,435
  • 6
  • 55
  • 106
0

How about doing some error handling. Like a Try Catch loop.

 try {
    //Run some code here
    }
 catch(err) {
    //Handle errors here
    }
Ben Strombeck
  • 1,391
  • 1
  • 16
  • 22
  • 1
    do something like navigate to Google.com, then set a Boolean as true if it works or false if it does not. There's a very high chance Google will not be going down... ever. So you have a better chance of actually testing if the application is online, and not just that the web resource you are trying to access is offline. – Ben Strombeck Mar 20 '12 at 11:56
  • 1
    Availablity of Google, and offline mode for my application - is huge difference. As I said in my question, I just stopping my local web service.. I'm not 'stopping' the internet. – Alexander Beletsky Mar 20 '12 at 11:59
0

Is it an option to ask localstorage when ajax call fails with a specific error (operation timeout)?

Or since the page (at least partially) is generated with server script you can include a request timestamp (or unique id) on your page with server-side script and put it to localstorage. Then you can see if the page is loaded from cache by checking stored id against the rendered one.

09-45
  • 48
  • 4
0

The best option might be to use the error event of the jQuery $.get() function to query localStorage rather than your webserver. This has the benefit of falling back if your server becomes unreachable as well as if the users entire internet is unreachable.

$.get({
  success: //deal with postback from ajax call,
  error: //Whoops no access to server deal with it in a local way
})
Simon West
  • 3,498
  • 1
  • 22
  • 26