I am accessing a link on my site that will provide a new image each time it is accessed.
The issue I am running into is that if I try to load the image in the background and then update the one on the page, the image doesn't change--though it is updated when I reload the page.
var newImage = new Image();
newImage.src = "http://localhost/image.jpg";
function updateImage()
{
if(newImage.complete) {
document.getElementById("theText").src = newImage.src;
newImage = new Image();
number++;
newImage.src = "http://localhost/image/id/image.jpg?time=" + new Date();
}
setTimeout(updateImage, 1000);
}
Headers as FireFox sees them:
HTTP/1.x 200 OK
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: image/jpeg
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Server: Microsoft-HTTPAPI/1.0
Date: Thu, 02 Jul 2009 23:06:04 GMT
I need to force a refresh of just that image on the page. Any ideas?
As an alternative to...
...it seems that...
...is sufficient to fool the browser cache without bypassing any upstream caches, assuming you returned the correct
Cache-Control
headers. Although you can use......you lose the benefits of the
If-Modified-Since
orIf-None-Match
headers, so something like......should prevent the browser from re-downloading the entire image if it hasn't actually changed. Tested and working on IE, Firefox, and Chrome. Annoyingly it fails on Safari unless you use...
...although this still may be preferable to filling upstream caches with hundreds of identical images, particularly when they're running on your own server. ;-)
Update (2014-09-28): Nowadays it looks like
Cache-Control: no-store
is needed for Chrome as well.One answer is to hackishly add some get query parameter like has been suggested.
A better answer is to emit a couple of extra options in your HTTP header.
By providing a date in the past, it won't be cached by the browser.
Cache-Control
was added in HTTP/1.1 and the must-revalidate tag indicates that proxies should never serve up an old image even under extenuating circumstances, and thePragma: no-cache
isn't really necessary for current modern browsers/caches but may help with some crufty broken old implementations.I've seen a lot of variation in answers for how to do this, so I thought I'd summarize them here (plus add a 4th method of my own invention):
(1) Add a unique cache-busting query parameter to the URL, such as:
Pros: 100% reliable, quick & easy to understand and implement.
Cons: Bypasses caching altogether, meaning unnecessary delays and bandwidth use whenever the image doesn't change between views. Will potentially fill browser cache (and any intermediate caches) with many, many copies of exactly the same image! Also, requires modifying image URL.
When to use: Use when image is constantly changing, such as for a live webcam feed. If you use this method, make sure to serve the images themselves with
Cache-control: no-cache
HTTP headers!!! (Often this can be set up using a .htaccess file). Otherwise you'll be progressively filling caches up with old versions of the image!(2) Add query parameter to the URL that changes only when the file does, e.g.:
(That's PHP server-side code, but the important point here is just that a ?m=[file last-modified time] querystring is appended to the filename).
Pros: 100% reliable, quick & easy to understand and implement, and preserves caching advantages perfectly.
Cons: Requires modifying the image URL. Also, a little more work for the server - it has to get access to the file-last-modified time. Also, requires server-side information, so not suitable for a purely client-side-only solution to check for a refreshed image.
When to use: When you want to cache images, but may need to update them at the server end from time to time without changing the filename itself. AND when you can easily ensure that the correct querystring is added to every image instance in your HTML.
(3) Serve your images with the header
Cache-control: max-age=0, must-revalidate
, and add a unique memcache-busting fragment identifier to the URL, such as:The idea here is that the cache-control header puts images in the browser cache, but immediately markes them stale, so that and every time they are re-displayed the browser must check with the server to see if they've changed. This ensures that the browser's HTTP cache always returns the latest copy of the image. However, browsers will often re-use an in-memory copy of an image if they have one, and not even check their HTTP cache in that case. To prevent this, a fragment identifier is used: Comparison of in-memory image
src
's includes the fragment identifier, but it gets stripped of before querying the HTTP cache. (So, e.g.,image.jpg#A
andimage.jpg#B
might both be displayed from theimage.jpg
entry in the browser's HTTP cache, butimage.jpg#B
would never be displayed using in-memory retained image data from whenimage.jpg#A
was last displayed).Pros: Makes proper use of HTTP caching mechanisms, and uses cached images if they haven't changed. Works for servers that choke on a querystring added to a static image URL (since servers never see fragment identifiers - they're for the browsers' own use only).
Cons: Relies on somewhat dubious (or at least poorly documented) behaviour of browsers, in regard to images with fragment identifiers in their URLs (However, I've tested this successfully in FF27, Chrome33, and IE11). Does still send a revalidation request to the server for every image view, which may be overkill if images only change rarely and/or latency is a big issue (since you need to wait for the revalidation response even when the cached image is still good). Requires modifying image URLs.
When to use: Use when images may change frequently, or need to be refreshed intermittently by the client without server-side script involvement, but where you still want the advantage of caching. For example, polling a live webcam that updates an image irregularly every few minutes. Alternatively, use instead of (1) or (2) if your server doesn't allow querystrings on static image URLs.
(4) Forcibly refresh a particular image using Javascript, by first loading it into a hidden
<iframe>
and then callinglocation.reload(true)
on the iframe'scontentWindow
.The steps are:
Load the image to be refreshed into a hidden iframe. This is just a setup step - it can be done long in advance the actual refresh, if desired. It doesn't even matter if the image fails to load at this stage!
Once that's done, blank out all copies of that image on your page(s) or anywhere in any DOM nodes (even off-page ones stored in javascript variables). This is necessary because the browser may otherwise display the image from a stale in-memory copy (IE11 especially does this): You need to ensure all in-memory copies are cleared, before refreshing the HTTP cache. If other javascript code is running asynchronously, you may also need to prevent that code from creating new copies of the to-be-refreshed image in the meantime.
Call
iframe.contentWindow.location.reload(true)
. Thetrue
forces a cache bypass, reloading directly from the server and overwriting the existing cached copy.Once it's finished re-loading, restore the blanked images. They should now display the fresh version from the server!
For same-domain images, you can load the image into the iframe directly. For cross-domain images, you have to instead load a HTML page from your domain that contains the image in an
<img>
tag, otherwise you'll get an "Access Denied" error when trying to calliframe.contentWindow.reload(...)
.Pros: Works just like the image.reload() function you wish the DOM had! Allows images to by cached normally (even with in-the-future expiry dates if you want them, thus avoiding frequent revalidation). Allows you to refresh a particular image without altering the URLs for that image on the current page, or on any other pages, using only client-side code.
Cons: Relies on Javascript. Not 100% guaranteed to work properly in every browser (I've tested this successfully in FF27, Chrome33, and IE11 though). Very complicated relative to the other methods.
When to use: When you have a collection of basically static images that you'd like cached, but you still need to be able to update them occasionally and get immediate visual feedback that the update took place. (Especially when just refreshing the whole browser page wouldn't work, as in some web apps built on AJAX for example). And when methods (1)-(3) aren't feasible because (for whatever reason) you can't change all the URLs that might potentially display the image you need to have updated. (Note that using those 3 methods the image will be refreshed, but if another page then tries to displays that image without the appropriate querystring or fragment identifier, it may show an older version instead).
The details of implementing this in a fairy robust and flexible manner are given below:
Let's assume your website contains a blank 1x1 pixel .gif at the URL path
/img/1x1blank.gif
, and also has the following one-line PHP script (only required for applying forced refresh to cross-domain images, and can be rewritten in any server-side scripting language, of course) at the URL path/echoimg.php
:Then, here's a realistic implementation of how you might do all this in Javascript. It looks a bit complicated, but there's a lot of comments, and the important function is just forceImgReload() - the first two just blank and un-blank images, and should be designed to work efficiently with your own HTML, so code them as works best for you; much of the complications in them may be unnecessary for your website:
Then, to force a refresh of an image located on the same domain as your page, you can just do:
To refresh an image from somewhere else (cross-domain):
A more advanced application might be to reload an image after uploading a new version to your server, preparing the initial stage of the reload process simultaneous with the upload, to minimize the visible reload delay to the user. If you're doing the upload via AJAX, and the server is returning a very simple JSON array [success, width, height] then your code might look something like this:
A final note: Although this topic is about images, it potentially applies to other kinds of files or resources also. For example, preventing the use of stale script or css files, or perhaps even refreshing updated PDF documents (using (4) only if set up to open in-browser). Method (4) might require some changes to the above javascript, in these cases.
After creating the new image, are you removing the old image from the DOM and replacing it with the new one?
You could be grabbing new images every updateImage call, but not adding them to the page.
There are a number of ways to do it. Something like this would work.
After getting that working, if there are still problems it is probably a caching issue like the other answers talk about.