API to check if a site has been served from browser cache - javascript

We would like to know from where the initial html document itself was served, either directly from the browser cache, our cdn cache or from origin. The later are easy (since our cdn adds server-timing to indicate a cache hit/miss), but figuring out if the document was served directly from the browser turned out more difficult.
I know about developer tools/network tab and how Chrome for example can show this information, but this question is specifically about any JavaScript API that can be used to detect and report it to us.
So far I've tried three things:
var isCached = performance.getEntriesByType("navigation")[0].transferSize === 0; from this answer, but today this seems to report the previous transferSize. When I try the same with the latest Chrome, I never get transferSize === 0, even when the devTools show me that it was cached. Possibly it only works for other resources, but not the html document itself.
var isCached = window.performance.navigation.type === 2 according to this answer gets the navigation type (in this case backward/forward), which is not always a true indicator of the document being cached. E.g. clicking a link is of type navigation and can also be cached.
Storing the timestamp in the document itself as suggested here on the server and comparing it does not work either, especially since we are using a cdn that has its own cache. We wouldn't be able to differentiate between a cached version from cdn or the browser.

From the MDN documentation and the PerformanceNavigationTiming interface described here, we can see that :
the requestStart attribute returns the time immediately before the user agent starts requesting the current document from the server, or from the HTTP cache or from local resources
We also have at our disposal the responseStart attribute :
responseStart returns the time after the user agent receives the first byte of the response from the server, or from the HTTP cache or from local resources
So, you should be able to detect when your initial HTML Document is served from the browser cache when the timing between the requestStart and responseStart is identical or almost identical.
It will be something like the following:
const timingDelta = 10; // to be conservative, but should be less than 5ms
const performanceEntry = performance.getEntriesByName("<URL of your document>")[0]; // ex: performance.getEntriesByName("https://www.google.com/")[0];
if (performanceEntry.responseStart - performanceEntry.requestStart < delta) {
console.log('document was served from cache');
}
// that info is also available on the performance.timing object but it's deprecated
// for your information, that would look like this:
if (performance.timing.responseStart - performance.timing.resquestStart < delta) { ... }

Why not checking http response code ?
Especially the 3xx codes.
304 Not Modified
Indicates that the resource has not been modified since the version specified by the request headers If-Modified-Since or If-None-Match. In such case, there is no need to retransmit the resource since the client still has a previously-downloaded copy.
See https://en.wikipedia.org/wiki/List_of_HTTP_status_codes

Related

How can I access the resources saved in the cache by a ServiceWorker?

I'm trying to build a webpage that uses ServiceWorker. I followed this example (for Chrome 45+), which seems to cache some data.
I tried to access the cached data but without success.
Is it possible to find the cached data via the Chrome console (similarly to Local Storage)?
Is there any simple JS code I can run from the console to get it?
Yes, you can see what's in the cache. Looking at the source code from the sample repository you're using, I see that it is storing the cached urls in a cache called CURRENT_CACHES['post-message']. If you're in the service worker (go to chrome://serviceworker-internals/, find the relevant service worker, and inspect it), this snippet of code will log the urls currently stored in that cache:
caches.open(CURRENT_CACHES['post-message']).then(function(cache) {
cache.keys().then(function(requests) {
var urls = requests.map(function(request) {
return request.url;
});
console.log(urls.sort());
});
});
Basically you're just opening the cache, calling keys() on it, and logging the url for each key (or cache record) that is returned.
Elevating this out of a comment:
The Cache Storage API is also exposed as window.caches in recent versions of Chrome, so you can execute that code from the DevTools in a controlled page, without going to the service worker DevTools. It's also exposed visually in the DevTools' Resources tab: twitter.com/jeffposnick/status/546494702842028032 – Jeff Posnick Sep 2 '15 at 17:51
With thanks to Jeff P.

How to force client reload after deployment?

I'm using the MEAN stack (mongo, express, angular and node). I'm deploying relatively frequently to production...every couple of days. My concern is that I'm changing the client side code and the API at times and I would rather not have to ensure backwards compatibility of the API with previous versions of the client code.
In such a scenario, what is the most effective way of ensuring that all clients reload when I push to production? I have seen that Evernote for example has a pop-up that says something along the lines of please reload your browser for the latest version of Evernote. I would like to do something similiar...do I need to go down the path of socket.io or sock.js or am I missing something simple and there is a simpler way to achieve this?
Update:
AppCache was deprecated summer 2015 so the below is no longer the best solution. The new recommendation is to use Service Workers instead. However, Service Workers are currently still experimental with sketchy (read: probably no) support in IE and Safari.
Alternatively, many build tools now seamlessly incorporate cache-busting and file "versioning" techniques to address OPs question. WebPack is arguably the current leader in this space.
This might be a good use case for using HTML5's AppCache
You'd probably want to automate some of these steps into your deployment scripts, but here is some code you might find useful to get you started.
First, create your appcache manifest file. This will also allow you to cache resources in the client's browser until you explicitly modify the appcache manifest file's date.
/app.appcache:
CACHE MANIFEST
#v20150327.114142
CACHE:
/appcache.js
/an/image.jpg
/a/javascript/file.js
http://some.resource.com/a/css/file.css
NETWORK:
*
/
In app.appcache, the comment on line #v20150327.114142 is how we indicate to the browser that the manifest has changed and resources should be reloaded. It can be anything, really, as long as the file will look different to the browser from the previous version. During deployment of new code in your application, this line should be modified. Could also use a build ID instead.
Second, on any pages you want to use the appcache, modify the header tag as such:
<html manifest="/app.appcache"></html>
Finally, you'll need to add some Javascript to check the appcache for any changes, and if there are, do something about it. Here's an Angular module. For this answer, here's a vanilla example:
appcache.js:
window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
// Browser downloaded a new app cache.
// Swap it in and reload the page to get the latest hotness.
window.applicationCache.swapCache();
if (confirm('A new version of the application is available. Would you like to load it?')) {
window.location.reload();
}
}
else {
// Manifest didn't changed. Don't do anything.
}
}, false);
Alternatively, if AppCache won't work for your situation, a more ghetto solution would be to create a simple API endpoint that returns the current build ID or last deployment date-time. Your Angular application occasionally hits this endpoint and compares the result to it's internal version, and if different, reloads itself.
Or, you may consider a live-reload script (example), but, while very helpful in development, I'm not sure how good of an idea it is to use live/in-place-reloading of assets in production.
I will tell you my problem first then I will recommend a tentative solution. I wanted to force my user to log out and then log in when a production build is been deployed. At any point in time, there will be two versions of software deployed on production. A version which software which FE knows and a version which Backend knows. Most of the time they would be the same. At any point in time if they go out of sync then we need to reload the client to let the client know that a new production build has been pushed.
I am assuming 99.99% of the time the backend would have the knowledge of the latest version of the deployed software on production.
following are the two approaches which I would love to recommend:-
The backend API should always return the latest version of the software in the response header. On the frontend, we should have a common piece of code that would check if the versions returned by the API and that present on the FE are the same. if not then reload.
Whenever a user logs in. the BE should encode the latest software version in the JWT. And the FE should keep sending this as a bearer token along with every API request. The BE should also write a common interceptor for every API request. which would compare the software version in the JWT received from the API request and the
Maybe you can add hash to your client code file name. eg app-abcd23.js.
So the browser will reload the file instead of get it from cache. or you can just add the hash to url.eg app.js?hash=abcd23 but some browser may still use the cached version.
i know rails has assets-pipline to handle it, but i am not familiar with MEAN stack. there should be some package in npm for that purpose.
And i dont think it is really necessary to use socket.io if you want to notify the user their client code is out of date. you can define your version in both html meta tag and js file,if mismatch, show a popup and tell the user to refresh.
Try to limit your js/files to expire within smaller periodic time, ie: 1 days.
But in case you want something that pop-out and tell your user to reload (ctrl+f5) their browser, then simply make a script that popup that news if you just changed some of your files, mark the ip/session who have just reload/told to reload, so they will not be annoyed with multiple popup.
I was facing the same problem recently. I fixed this by appending my app's build number with my js/css files. All my script and style tags were included by a script in a common include files so it was trivial to add a 'build number' at the end of the js/css file path like this
/foo/bar/main.js?123
This 123 is a number that I keep track of in my same header file. I increment it whenever I want the client to force download all the js files of the app. This gives me control over when new versions are downloaded but still allows the browser to leverage cache for every request after the first one. That is until I push another update by increment the build number.
This also means I can have a cache expiry header of however long I want.
Set a unique key to local storage during the build process
I am using react static and loading up my own data file, in there i set the ID each time my content changes
Then the frontend client reads the key with from local storage
(if the key does not exist it must be the first visit of the browser)
if the key from local storage does not match it means the content has changed
fire line below to force reload
window.replace(window.location.href + '?' + key)
in my case i had to run this same line again a second latter
like
setTimeout( (window.replace(window.location.href + '?' + key))=> {} , 1000)
full code below:
const reloadIfFilesChanged = (cnt: number = 0, manifest: IManifest) => {
try {
// will fail if window does not exist
if (cnt > 10) {
return;
}
const id = localStorage.getItem('id');
if (!id) {
localStorage.setItem('id', manifest.id);
} else {
if (id !== manifest.id) {
// manifest has changed fire reload
// and set new id
localStorage.setItem('id', manifest.id);
location.replace(window.location.href + '?' + manifest.id);
setTimeout(() => {
location.replace(window.location.href + '?' + manifest.id + '1');
}, 1000);
}
}
} catch (e) {
// tslint:disable-next-line:no-parameter-reassignment
cnt++;
setTimeout(() => reloadIfFilesChanged(cnt, manifest), 1000);
}
};

Why do browsers inefficiently make 2 requests here?

I noticed something odd regarding ajax and image loading. Suppose you have an image on the page, and ajax requests the same image - one would guess that ajax requests would hit the browser cache, or it should at least only make one request, the resulting image going to the page and the script that wants to read/process the image.
Surprisingly, I found that even when the javascript waits for the entire page to load, the image request still makes a new request! Is this a known bug in Firefox and Chrome, or something bad jQuery ajax is doing?
Here you can see the problem, open Fiddler or Wireshark and set it to record before you click "run":
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<div id="something" style="background-image:url(http://jsfiddle.net/img/logo-white.png);">Hello</div>
<script>
jQuery(function($) {
$(window).load(function() {
$.get('http://jsfiddle.net/img/logo-white.png');
})
});
</script>
Note that in Firefox it makes two requests, both resulting in 200-OK, and sending the entire image back to the browser twice. In Chromium, it at least correctly gets a 304 on second request instead of downloading the entire contents twice.
Oddly enough, IE11 downloads the entire image twice, while it seems IE9 aggressively caches it and downloads it once.
Ideally I would hope the ajax wouldn't make a second request at all, since it is requesting exactly the same url. Is there a reason css and ajax in this case usually have different caches, as though the browser is using different cache storage for css vs ajax requests?
I use the newest Google Chrome and it makes one request. But in your JSFIDDLE example you are loading jQuery twice. First with CSS over style attribute and second in your code over script tag. Improved: JSFIDDLE
<div id="something" style="background-image:url('http://jsfiddle.net/img/logo-white.png');">Hello</div>
<script>
jQuery(window).load(function() {
jQuery.get('http://jsfiddle.net/img/logo-white.png');
});
// or
jQuery(function($) {
jQuery.get('http://jsfiddle.net/img/logo-white.png');
});
</script>
jQuery(function($) {...} is called when DOM is ready and jQuery(window).load(...); if DOM is ready and every image and other resources are loaded. To put both together nested makes no sense, see also here: window.onload vs $(document).ready()
Sure, the image is loaded two times in Network tab of the web inspector. First through your CSS and second through your JavaScript. The second request is probably cached.
UPDATE: But every request if cached or not is shown in this tab. See following example: http://jsfiddle.net/95mnf9rm/4/
There are 5 request with cached AJAX calls and 5 without caching. And 10 request are shown in 'Network' tab.
When you use your image twice in CSS then it's only requested once. But if you explicitly make a AJAX call then the browser makes an AJAX call. As you want. And then maybe it's cached or not, but it's explicitly requested, isn't it?
This "problem" could a be a CORS pre-flight test.
I had noticed this in my applications awhile back, that the call to retrieve information from a single page application made the call twice. This only happens when you're accessing URLs on a different domain. In my case we have APIs we've built and use on a different server (a different domain) than that of the applications we build. I noticed that when I use a GET or POST in my application to these RESTFUL APIs the call appears to be made twice.
What is happening is something called pre-flight (https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS), an initial request is made to the server to see if the ensuing call is allowed.
Excerpt from MDN:
Unlike simple requests, "preflighted" requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. In particular, a request is preflighted if:
It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)
Your fiddle tries to load a resource from another domain via ajax:
I think I created a better example. Here is the code:
<img src="smiley.png" alt="smiley" />
<div id="respText"></div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(window).load(function(){
$.get("smiley.png", function(){
$("#respText").text("ajax request succeeded");
});
});
</script>
You can test the page here.
According to Firebug and the chrome network panel the image is returned with the status code 200 and the image for the ajax request is coming from the cache:
Firefox:
Chrome:
So I cannot find any unexpected behavior.
Cache control on Ajax requests have always been a blurred and buggy subject (example).
The problem gets even worse with cross-domain references.
The fiddle link you provided is from jsfiddle.net which is an alias for fiddle.jshell.net. Every code runs inside the fiddle.jshell.net domain, but your code is referencing an image from the alias and browsers will consider it a cross-domain access.
To fix it, you could change both urls to http://fiddle.jshell.net/img/logo-white.png or just /img/logo-white.png.
The helpful folks at Mozilla gave some details as to why this happens. Apparently Firefox assumes an "anonymous" request could be different than normal, and for this reason it makes a second request and doesn't consider the cached value with different headers to be the same request.
https://bugzilla.mozilla.org/show_bug.cgi?id=1075297
This may be a shot in the dark, but here's what I think is happening.
According to,
http://api.jquery.com/jQuery.get/
dataType
Type: String
The type of data expected from the server.
Default: Intelligent Guess (xml, json, script, or html).
Gives you 4 possible return types. There is no datatype of image/gif being returned. Thus, the browser doesn't test it's cache for the src document as it is being delivered a a different mime type.
The server decides what can be cached and for how long. However, it again depends on the browser, whether or not to follow it. Most web browsers like Chrome, Firefox, Safari, Opera and IE follow it, though.
The point that I want to make here, is that your web sever might be configured to not allow your browser to cache the content, thus, when you request the image through CSS and JS, the browser follows your server's orders and doesn't cache it and thus it requests the image twice...
I want JS-accessible image
Have you tried to CSS using jQuery? It is pretty fun - you have full CRUD (Create, read, update, delete) CSS elements. For example do image resize on server side:
$('#container').css('background', 'url(somepage.php?src=image_source.jpg'
+ '&w=' + $("#container").width()
+ '&h=' + $("#container").height() + '&zc=1');
Surprisingly, I found that even when the javascript waits for the entire page to load, the image request still makes a new request! Is this a known bug in Firefox and Chrome, or something bad jQuery ajax is doing?
It is blatantly obvious that this is not a browser bug.
The computer is deterministic and does what exactly you tell it to (not want you want it to do). If you want to cache images it is done in server side. Based on who handles caching it can be handled as:
Server (like IIS or Apache) cache - typically caches things that are reused often (ex: 2ce in 5 seconds)
Server side application cache - typically it reuses server custom cache or you create sprite images or ...
Browser cache - Server side adds cache headers to images and browsers maintain cache
If it is not clear then I would like to make it clear : You don't cache images with javascript.
Ideally I would hope the ajax wouldn't make a second request at all, since it is requesting exactly the same url.
What you try to do is to preload images.
Once an image has been loaded in any way into the browser, it will be
in the browser cache and will load much faster the next time it is
used whether that use is in the current page or in any other page as
long as the image is used before it expires from the browser cache.
So, to precache images, all you have to do is load them into the
browser. If you want to precache a bunch of images, it's probably best
to do it with javascript as it generally won't hold up the page load
when done from javascript. You can do that like this:
function preloadImages(array) {
if (!preloadImages.list) {
preloadImages.list = [];
}
for (var i = 0; i < array.length; i++) {
var img = new Image();
img.onload = function() {
var index = preloadImages.list.indexOf(this);
if (index !== -1) {
// remove this one from the array once it's loaded
// for memory consumption reasons
preloadImages.splice(index, 1);
}
}
preloadImages.list.push(img);
img.src = array[i];
}
}
preloadImages(["url1.jpg", "url2.jpg", "url3.jpg"]);
Then, once they've been preloaded like this via javascript, the browser will have them in its cache and you can just refer to the normal URLs in other places (in your web pages) and the browser will fetch that URL from its cache rather than over the network.
Source : How do you cache an image in Javascript
Is there a reason css and ajax in this case usually have different caches, as though the browser is using different cache storage for css vs ajax requests?
Even in absence of information do not jump to conclusions!
One big reason to use image preloading is if you want to use an image
for the background-image of an element on a mouseOver or :hover event.
If you only apply that background-image in the CSS for the :hover
state, that image will not load until the first :hover event and thus
there will be a short annoying delay between the mouse going over that
area and the image actually showing up.
Technique #1 Load the image on the element's regular state, only shift it away with background position. Then move the background
position to display it on hover.
#grass { background: url(images/grass.png) no-repeat -9999px -9999px; }
#grass:hover { background-position: bottom left; }
Technique #2 If the element in question already has a background-image applied and you need to change that image, the above
won't work. Typically you would go for a sprite here (a combined
background image) and just shift the background position. But if that
isn't possible, try this. Apply the background image to another page
element that is already in use, but doesn't have a background image.
#random-unsuspecting-element {
background: url(images/grass.png) no-repeat -9999px -9999px; }
#grass:hover { background: url(images/grass.png) no-repeat; }
The idea create new page elements to use for this preloading technique
may pop into your head, like #preload-001, #preload-002, but that's
rather against the spirit of web standards. Hence the using of page
elements that already exist on your page.
The browser will make the 2 requests on the page, cause an image called from the css uses a get request (not ajax) too before rendering the entire page.
The window load is similar to de attribute, and is loading before the rest of the page, then, the image from the Ajax will be requested first than the image on the div, processed during the page load.
If u would like to load a image after the entire page is loaded, u should use the document.ready() instead

How to use/create a MANIFEST, handle appCache events/errors and the use of swapCache

How do you use and create a MANIFEST file (structure),
handle appCache events and errors,
and when is swapCache needed?
Use Application Cache With Manifest
To use application cache you need to reference to the manifest file inside the HTML document, like this:
<html manifest="manifest.appcache"/>
The manifest file itself needs a predetermined layout to work.
CACHE MANIFEST is mandatory, and needs to be at the top (so that when the browser checks if it is a cache manifest, it returns true).
CACHE is optional, but recommended, and used for referring to the files you want cached locally.
FALLBACK is optional, and is used to specify file(s) that should be used if the specified one (in CAHCE) is unavailable. The first file specified (in FALLBACK) is the original file, and the second file is the one that will be used if the original file is unavailable.
NETWORK should be considered to be mandatory, but isn't. It is used to specify what files needs an internet connection (isn't cached). Using "*" (without the brackets) specifies that all other files except the ones mentioned in CACHE, needs an active internet connection.
Example:
CACHE MANIFEST
CACHE:
YourFirstFile.html
YourSecondFile.png
fallbackFile1.html
fallbackFile2.png
Etc.css
FALLBACK:
YourFirstFile.html fallbackFile1.html
YourSecondFile.png fallbackFile2.png
NETWORK:
*
The manifest (and its specified resources) is only checked upon page load (when the user enters the site).
Side note: The manifest file is case sensitive.
Handling events triggered in application cache
The first thing I want to say is appCache is really window.applicationCache, so it needs to be declared (var appCache = window.applicationCache;).
When a user enters the site for the first time (or the manifest cache isn’t present), the following events are triggered; if everything works as it should:
Creating Application Cache with manifest
Application Cache Checking
Application Cache Downloading
Application Cache Progress (0 of X)
Application Cache Cached
Let’s break it down.
The first (Creating Application Cache) specifies a cache “file/folder” for the browser to use later on.
The second (Application Cache Checking) "checking", looks inside the manifest file to see what it needs to cache.
The third (Application Cache Downloading) "downloading", begins the download process of the files specified in the manifest.
The fourth (Application Cache Progress) "progress", keeps track of the downloading progress (this is triggered for each file).
The fifth (Application Cache Cached) "cached", simply says “i’m done” caching the files, and everything went as it should.
What does this mean? It means that we can have some control over the events, and can trigger our own events if we’d like to.
So by listening to the progress event, we can display a progress bar, a notification with steps or really whatever we want.
appCache.addEventListener("progress", function(event) {
console.log(event.loaded + " of " + event.total);
}, false);
Wait, what did I just do?
I added an event listener with an anonymous-function. Within this function I pass on an “event” from what we are listening to (downloading), and simply logged how many files has been cached thus far and how many files there are in total.
Let's do this on all the events mentioned, from the first called event, to the last:
appCache.addEventListener("checking", function(event) {
console.log("Checking for updates.");
}, false);
appCache.addEventListener("downloading", function(event) {
console.log("Started Download.");
}, false);
appCache.addEventListener("progress", function(event) {
console.log(event.loaded + " of " + event.total + " downloaded.");
}, false);
appCache.addEventListener("cached", function(event) {
console.log("Done.");
}, false);
Now these events do what I want them to.
These are the appCache events:
checking - Always the first event triggered. Checks for an update in the manifest.
downloading - Triggered when an update is found. Downloads resources specified in the manifest.
progress - Triggered for each resource currently downloading. Tracks the progress (by file).
error - Triggered if 404, 410 network error occurs, or the manifest file was changed while downloading.
obsolete - Triggered if 404, 410 network error occurs, or the manifest file doesn't exist (on the server). Note that this event will delete previous (and current) application cache.
cached - (Only) Triggered the first time the resources specified in the manifest is cached.
noupdate - Triggered if no change has been made to the manifest since the last cache update.
updateready - Triggered if new resources are downloaded.
Scenario handling (error(s), events and triggers)
What if something goes wrong? We can handle that with error and/or obsolete.
error is triggered when something goes wrong while updating.
e.g.
A file specified in the manifest does not exist on the server.
The manifest is changed while downloading.
obsolete is triggered when the manifest file doesn't exist (on the server).
e.g.
The manifest file is deleted from the server.
The website points to an invalid url/path (<html manifest="manifest.appcache"/>).
By listening to error, we can, for example, tell the user if something goes wrong:
appCache.addEventListener("error", function(event) {
if (navigator.onLine == true) { //If the user is connected to the internet.
alert("Error - Please contact the website administrator if this problem consists.");
} else {
alert("You aren't connected to the internet. Some things might not be available.");
}
}, false);
Here I checked if the user have an active internet connection or not. Keep in mind that this is just an example, telling the user might not be necessary (depending on your website).
We can do the same thing with obsolete, but we might not want to tell the user about it, as this is a server side problem:
appCache.addEventListener("obsolete", function(event) {
console.log("Obsolete - no resources are cached, and previous cache(s) are now deleted.");
}, false);
swapCache
Now this is a tricky one. The main questions about swapCache is; "What does it do?", "Is it useful/needed?" and "Should it be used?".
swapCache is used to replace the old cache with the new one. It can only be used inside the updateready event (if used elsewhere, it will throwback an error).
"What does it do?": swapCache does what it says, swaps the current cache with a new one.
"Is it useful/needed?": appCache is useful, the main reason to use it would be to make sure the newsiest cache available is used. Altho this seems like a thing that should work by itself, that's not always the case. For example, some browsers don't always use the latest cache as haven't gotten the message that it needs to (the iPhone is a good example ). An image might be cached, then deleted/renamed, then cached, and so on. In the end, the browser might use an old cache to display that image because of the reference it already has with the stored caches(s). Bottom line: Is it useful? yes. Is it needed? no.
"Should it be used?": Personally I would say yes. But it depends on what your page does. If the criteria from the example above matches your resource handling, then yes. Otherwise it wouldn't really matter.
so by adding an event listener to updateready, we can include swapCache:
appCache.addEventListener("updateready", function(event) {
appCache.swapCache();
window.reload();
}, false);
(appCache) Event variables:
progress.
total
loaded
lengthComputable
GENERAL (for all):
clipboardData
cancelBubble
returnValue
srcElement
defaultPrevented
timeStamp
cancelable
bubbles
eventPhase
currentTarget
target
type
stopPropagation
preventDefault
initEvent
stopImmediatePropagation
Nice external pages:
http://www.html5rocks.com/en/tutorials/appcache/beginner/ - appCache basics.
http://www.htmlgoodies.com/html5/other/html-5-appcache-by-example.html - appCache example.
http://www.jefclaes.be/2012/04/visualizing-offline-application-cache.html - manifest FALLBACK.
Is swapCache() required in HTML5 offline apps? - swapCache information (read the comments as well).
https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching - general HTTP cache information.

How can I tell when a web page resource is cached?

Is there a way in JavaScript for me to tell whether a resource is already in the browser cache?
We're instrumenting a fraction of our client-side page views so that we can get better data on how quickly pages are loading for our users. The first time users arrive on our site, a number of resources (JS, CSS, images) are cached by the browser, so their initial pageview is going to be slower than subsequent ones.
Right now, that data is mixed together, so it's hard to tell an initial page load from a subsequent pageview that's slow for some other reason. I'd love a cross-browser way to check to see whether the cache is already primed, so that I can segregate the two sorts of pageview and analyze them separately.
You should use TransferSize:
window.performance.getEntriesByName("https://[resource-name].js")[0].transferSize
To verify it, you can run the above line on Chrome...
If the browser has caching enabled and your resource was previously loaded with proper cache-control header, transferSize should be 0.
If you disable caching (Network tab -> Disable cache) and reload, transferSize should be > 0.
There isn't a JavaScript API for checking if a resource is cached. I think the best you can do is check how long it took to load the resources, and bucket the ones with shorter load times together.
At the top of the page:
<script>var startPageLoad = new Date().getTime();</script>
On each resource:
<img src="foo.gif" onload="var fooLoadTime = startPageLoad - new Date().getTime()">
<script src="bar.js" onload="var barLoadTime = startPageLoad - new Date().getTime()">
When reporting load times:
var fooProbablyCached = fooLoadTime < 200; // Took < 200ms to load foo.gif
var barProbablyCached = barLoadTime < 200; // Took < 200ms to load bar.gif
You may need to use onreadystatechange events instead of onload in IE.
You need a plug-in to do this. Firebug can tell you on the "NET" tab, once you install it (for Firefox). JavaScript itself cannot see the browser's HTTP traffic.

Categories

Resources