Caching preloaded images possible over page switch? - javascript

I'm currently trying to preload images for a webpage I'm creating as those images are quite big.
Currently I know (thanks to another post here) how to handle the images themselves via preloading them (via javascript pre loading and then displaying them in a canvas).
BUT whenever I switch the page the preloaded images need to be preloaded again, thus they are not cached.
So my question is: Is there any possibility to cache these images?
(or is it even best to put them into a session variable?)
The images themselves are quite big and can take up 1.5MB each (in total there are 20 images alone in the part that is currently already in existence, which takes about 4 seconds to preload).
As infos if necessary:
I'm using an apache server and php as primary language with javascript as support.
Edit:
As I forgot to mention it: The webserver I will finally store the site on is an external one (hosting provider) so I won't be able to edit the webserversettings themselves there

If the images don't change, try something like this in .htaccess:
#Set caching on image files for 11 months
<filesMatch "\.(ico|gif|jpg|png)$">
ExpiresActive On
ExpiresDefault "access plus 11 month"
Header append Cache-Control "public"
</filesMatch>
If you think this is not the right approach, like the images may change, just eager-load the images right when the page hits (warning, definitely a hack):
(function(){
var hiddenCache = document.createElement("div");
hiddenCache.style.display = "none";
document.body.appendChild(hiddenCache);
// or for loop if ECMA 3
myEagerLoadedImageUrls.forEach(function(urlStr){
var hiddenImg = document.createElement("img");
hiddenImg.src = urlStr;
hiddenCache.appendChild(hiddenImg)
});
})()

The browser already caches the images in its memory and/or disk cache as long as the headers coming from the server aren't telling it to avoid caching. The browser cache endures across page loads. SO, if your images have been loaded once on the first page, they should be in the browser cache already for the second page and thus when requested on the second page, they should load locally and not have to be fetched over the internet.
If you're looking for client-side code that can be used to preload images, there are many examples:
How do you cache an image in Javascript
Image preloader javascript that supports events
Is there a way to load images to user's cache asynchronously?
FYI, it is possible in newer browsers to use a combination of Local Storage and data URIs to implement your own image caching, but I'd be surprised if there was any real world situation where that was required and if you have a lot of images, you may run into storage limits on Local Storage quicker than limits on the size of the browser cache.

Related

When Chrome clears disk cache?

I have one website which serves listener.js on the main page. I want to update this javascript file with some extra codes. But browsers (especially chrome) has memory and disk cache. Also HTTP cache of course. I tried something about that state. I tried just F5, the file loaded from memory cache. Then I killed chrome and opened the website again, javascript file loaded from the disk cache. So I have 2 questions;
When chrome clears disk cache?
How can I say to my visitors don't use any cache and get the new javascript file from my server?
Update:
Can I do this with no-cache Http header?
Removing temporarily cached file known as cache busting. It is useful because browser doesn't have to download these files again.
If it is causing issues, developers can force browsers to download new files. This is performed by re-naming file but there is a better way
src="js/listener.js" => src="js/listener.js?v=2"
Update:
Or hash like this => ?v=c298c7f8233d which is better than ?v=2 (comment by Tech Guy)
(Credits: 30-seconds)
Chrome doesn't auto clear disk cache unless this option is checked
Privacy settings > Content settings > Keep local data only until you quit browser
In which case, it deletes cache on closing the browser.
You usually prevent a client from saving your files in cache by hashing your filenames in
each build, which is the most common cache-busting technique. That means in every release, you will have a new file name and the old cached file won't matter. For instance
Most build tools like Webpack have cache-busting features that you can turn on.
You don't want to stop the user from caching at all, because caching is immensely useful and prevents repeated downloads. You just want to prevent downloads when you build a new release.
This solution worked for me.
let randomNum = Math.round(Math.random() * 10000);
src = "js/listener.js?" + randomNum;
Every time a random number will be generated and it'll be treated as a new request and won't be cached.

Prevent image to be cached with javascript

Recently I tried to make sure that some of the images on my website are not cached by the browser.
I came across several questions like
Preventing Images being cached in the browser
How to prevent browser image caching?
How to prevent browsers from caching an image?
But since a short time the solution that they provided stoped working for me.
I have serveral images on my website but there is only one that I do not want to cache.
I used <img src="/img/img.jpg?1275332" />
Where the number was the current time stamp.
Is there any other way to prevent the browser from caching?
And does any one has an idea why this isn't working (anymore)?
Edit:
The image that I do not want to cache is not a static image.
When a user changes one of his images, only the changed image need to be updated. Thats why I tried to add a timestamp after the changed image.
The application is also a SPA so there wont be any page refresh.
You can use a application-cache manifest file. For that you need to add it to your html page in following manner :
<!doctype html>
<html manifest="myapp.appcache">
<head>...</head>
<body>...</body>
In your application-cache manifest specify the image in the NETWORK section. The NETWORK section is used to specify urls that must never be cached and should always be retrieved from the network.
CACHE MANIFEST
CACHE:
#html page, scripts etc you want to cache
FALLBACK:
#fallback resource if cached version is not available.
NETWORK:
#image path you don't want to cache
More control of this whole process can be achieved by attaching event handlers to window.applicationCache events like onupdate, oncached, ondownloading, onprogress, onobsolete
I hope this would solve your issue.

How to speed up image loads from Angular/Mvc.net

I have an MVC.net website which serves images based on this old article:
http://blogs.msdn.com/b/miah/archive/2008/11/13/extending-mvc-returning-an-image-from-a-controller-action.aspx
My c# controller code looks like this:
public ActionResult GetThumbnail(string code)
{
byte[] image = _dataProvider.GetThumbnailImage(code);
return this.Image(image, "image/jpeg");
}
On the client side I have an AngularJS controller which loads up a search result set from the server. The result set includes a number of image URLs like this:
<tr ng-repeat="item in data.items | filter:filter" class="fixed-height-80">
<td>
<img ng-src="{{item.thumbnailUrl}}"/>
</td>
</tr>
The thumbnailUrl points to the GetThumbnail action on my MVC controller and is constructed server side in a model factory and returned to the Angular ready for use.
The problem is that the images load very slowly even thought they are only about 3kb per image. After the async search return is completed in the javascript the images appear one at a time, about one per second, until they are all loaded.
I put a Stopwatch in the C# on the .net controller and the loading of the image data from the dataProvider on the server side takes about 0.9ms But even with just ten images to serve it takes about six seconds before all the images are loaded in the page. The JS renders the links almost immedialtly, it's just the images that are slow.
How can I speed up image loading in this context?
Update
If I move the images into ~/images/image.jpg and route the url to point directly at the folder using Url.Content it doesn't seem to have the same issue. therefore the problem seems to be with the way the controller is serving the images - sometimes if can take < 10ms and other times over 2000ms for the same image, but it's unclear why.
Several options are available:
Caching the images in the browser/client-side by adding cache-control HTTP to the response headers.
Caching the images in the server-side (in-memory) instead of carrying-out an I/O operation to the file-system (IIS will cache frequently used images and serving them from memory).
Compression of HTTP response's resources using GZIP, for example (you should do it in your Web-Server).
Reduce images size/quality in the server (maybe while uploading them).
Use CSS image sprite technique: An image sprite is a collection of images put into a single image and by that, reducing the number of images that the browser need to load.
Use a dedicated CDN for serving your images faster and in turn, reduce the load-time on the server.
You should decide what's the best choice in your case.
UPDATE:
Another 2 options:
With ng-repeat, in each iteration of your results you're effectively accessing the server instead of accessing the browser cache - there could be hundreds of records. It would be better to send your images with cache-control HTTP response headers (A Beginner's Guide to HTTP Cache Headers) in order to prevent accessing the server again and again for fetching the images and reducing the repeated round-trips.
Pre-load your images into the browser cache: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/
Consider option to resize images once they loaded on the server and store thumbnails images on the server or CDN as well as orignal version. This will reduce server load and make image load as fast as getting image without any processing every time image requested.
Use a proper CDN or just serve it directly from virtual directories. Your current implementation is IIS is good and fast as a web server, .Net framework is good as a server-side technology.
A properly configured IIS will help you save bandwidth and file system I/O, if you need resizing capabilities, check out Image Resizer
It turns out that it's the MVC SessionState that causes this issue - although it's not entirely clear why at thgis stage.
Adding a new controller just for images and decorating it as below will disable the default session state behaviour and prevent the images getting stuck 'waiting' for ages.
[SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)]
public class ImageController : Controller
{
public ActionResult GetThumbnail(string code)
{
byte[] image = _dataProvider.GetThumbnailImage(code);
return this.Image(image, "image/jpeg");
}
}

Super-aggressive 'caching' technique

I had an idea on how to vastly speed up my website and ease the load on my server for cached objects, but I'm wondering if this is an extremely stupid idea before I spend all day thinking about it! Hear me out -
The localStorage object has a minimum of 2.5 MB (in Chrome, more here) which is good enough for most small sites. Which is why I am wondering - for small, static websites, would it be a good idea to basically save the entire site in a huge localStorage file and basically load the site from the visitor's own computer each time? To better explain my idea, here's some pseudo-code:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!--other head information-->
</head>
<body>
<script>
if (localStorage.getItem('cached_site')!=null) {
document.getElementsByTagName("body")[0].remove();
document.documentElement.innerHTML = localStorage.getItem('cached_site');
//Somehow stop loading the rest of the site (ajax?)
}
else {
//set localStorage var to the source code of the site.
//**This will be fleshed out to data/base64 all image resources as well**
localStorage.setItem('cached_site',document.documentElement.innerHTML);
//load the site as normal
}
</script>
</body>
</html>
This will save the contents of the body in a localStorage file called cached_site. There are some issues with the logic (like the "stop loading the site" part) but you get the idea.
Is this worth it? Potentially, requests could be completely cut from static content because it's all being loaded onto the user's computer. In order to update the content, maybe another value, perhaps a version number could be saved and checked in the else block.
My webhost limits the amount of requests I can get per day, which is why I thought of this. It's not a huge deal, but an interesting project nonetheless.
This idea will have issues with dynamic web sites... how will you treat dynamically generated web pages?
Another idea would be to save each page into a static html file on the server, and then serve the static page, which will be regenerated when needed.
You should also cache the static parts of your website, i.e. images, scripts, CSS, and store these in the cache of your visitors' browsers.
In Apache, you could use mod_expires, and then set up an .htaccess file like this:
### turn on the Expires engine
ExpiresActive On
<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|swf)(\.gz)?$">
ExpiresDefault "access plus 1 month"
FileETag None
</FilesMatch>
This will basically cache all of the static parts of your website in your visitors' browser cache, so they will stop refetching the same files over and over.
You should also try and combine your CSS/Javascript files, and ideally end up with 1-2 javascript files, and 1 CSS file, thus limiting the number of requests per client.
I would also suggest using Yahoo's YSlow and Google's PageSpeed Tools to profile your site. They both contain best practices on how to speed up your page here and here.
Here are some suggestions from Yahoo + Google, at a glance:
Minimize HTTP Requests (use combined files for JS/CSS, CSS sprites, image maps and inline images, where possible)
Add an Expires or a Cache-Control Header (like what has been explained above)
Properly configure ETags, or remove them
Gzip Components (e.g. with mod_deflate in Apache)
Make JavaScript and CSS External
Minify JavaScript and CSS (i.e. remove whitespace and newlines) - in PHP, you can use the minify script to do this
Optimize images

how to clear or replace a cached image

I know there are many ways to prevent image caching (such as via META tags), as well as a few nice tricks to ensure that the current version of an image is shown with every page load (such as image.jpg?x=timestamp), but is there any way to actually clear or replace an image in the browsers cache so that neither of the methods above are necessary?
As an example, lets say there are 100 images on a page and that these images are named "01.jpg", "02.jpg", "03.jpg", etc. If image "42.jpg" is replaced, is there any way to replace it in the cache so that "42.jpg" will automatically display the new image on successive page loads? I can't use the META tag method, because I need everuthing that ISN"T replaced to remain cached, and I can't use the timestamp method, because I don't want ALL of the images to be reloaded every time the page loads.
I've racked my brain and scoured the Internet for a way to do this (preferrably via javascript), but no luck. Any suggestions?
If you're writing the page dynamically, you can add the last-modified timestamp to the URL:
<img src="image.jpg?lastmod=12345678" ...
<meta> is absolutely irrelevant. In fact, you shouldn't try use it for controlling cache at all (by the time anything reads content of the document, it's already cached).
In HTTP each URL is independent. Whatever you do to the HTML document, it won't apply to images.
To control caching you could change URLs each time their content changes. If you update images from time to time, allow them to be cached forever and use a new filename (with a version, hash or a date) for the new image — it's the best solution for long-lived files.
If your image changes very often (every few minutes, or even on each request), then send Cache-control: no-cache or Cache-control: max-age=xx where xx is the number of seconds that image is "fresh".
Random URL for short-lived files is bad idea. It pollutes caches with useless files and forces useful files to be purged sooner.
If you have Apache and mod_headers or mod_expires then create .htaccess file with appropriate rules.
<Files ~ "-nocache\.jpg">
Header set Cache-control "no-cache"
</Files>
Above will make *-nocache.jpg files non-cacheable.
You could also serve images via PHP script (they have awful cachability by default ;)
Contrary to what some of the other answers have said, there IS a way for client-side javascript to replace a cached image. The trick is to create a hidden <iframe>, set its src attribute to the image URL, wait for it to load, then forcibly reload it by calling location.reload(true). That will update the cached copy of the image. You may then replace the <img> elements on your page (or reload your page) to see the updated version of the image.
(Small caveat: if updating individual <img> elements, and if there are more than one having the image that was updated, you've got to clear or remove them ALL, and then replace or reset them. If you do it one-by-one, some browsers will copy the in-memory version of the image from other tags, and the result is you might not see your updated image, despite its being in the cache).
I posted some code to do this kind of update here.
Change the image url like this, add a random string to the querystring.
"image1.jpg?" + DateTime.Now.ToString("ddMMyyyyhhmmsstt");
I'm sure most browsers respect the Last-Modified HTTP header. Send those out and request a new image. It will be cached by the browser if the Last-Modified line doesn't change.
You can append a random number to the image which is like giving it a new version. I have implemented the similar logic and it's working perfectly.
<script>
var num = Math.random();
var imgSrc= "image.png?v="+num;
$(function() {
$('#imgID').attr("src", imgSrc);
})
</script>
I found this article on how to cache bust any file
There are many ways to force a cache bust in this article but this is the way I did it for my image:
fetch('/thing/stuck/in/cache', {method:'POST', credentials:'include'});
The reason the ?x=timestamp trick is used is because that's the only way to do it on a per image basis. That or dynamically generate image names and point to an application that outputs the image.
I suggest you figure out, server side, if the image has been changed/updated, and if so then output your tag with the ?x=timestamp trick to force the new image.
No, there is no way to force a file in a browser cache to be deleted, either by the web server or by anything that you can put into the files it sends. The browser cache is owned by the browser, and controlled by the user.
Hence, you should treat each file and each URL as a precious resource that should be managed carefully.
Therefore, porneL's suggestion of versioning the image files seems to be the best long-term answer. The ETAG is used under normal circumstances, but maybe your efforts have nullified it? Try changing the ETAG, as suggested.
Change the ETAG for the image.
See http://en.wikipedia.org/wiki/URI_scheme
Notice that you can provide a unique username:password# combo as a prefix to the domain portion of the uri. In my experimentation, I've found that inclusion of this with a fake ID (or password I assume) results in the treatment of the resource as unique - thus breaking the caching as you desire.
Simply use a timestamp as the username and as far as I can tell the server ignores this portion of the uri as long as authentication is not turned on.
Btw - I also couldn't use the tricks above with a google map marker icon caching problem I was having where the ?param=timestamp trick worked, but caused issues with disappearing overlays. Never could figure out why this was happening, but so far so good using this method. What I'm unsure of, is if passing fake credentials will have any adverse server performance affects. If anyone knows I'd be interested to know as I'm not yet in high volume production.
Please report back your results.
Since most, if not all, answers and comments here are copies of parts the question, or close enough, I shall throw my 2 cents in.
I just want to point out that even if there is a way it is going to be difficult to implement. The logic of it traps us. From a logical stance telling the browser to replace it's cached images for each changed image on a list since a certain date is ideal BUT... When would you take the list down and how would you know if everyone has the latest version who would visit again?
So my 1st "suggestion", as the OP asked for, is this list theory.
How I see doing this is:
A.) Have a list that our dynamic and manual changed image urls can be stored.
B.) Set a dead date where the catch will be reset and the list will be truncated regardless.
C.0) Check list on site entrance vs browser via i frame which could be ran in the background with a shorter cache header set to re-cache them all against the farthest date on the list or something of that nature.
C.1) Using the Iframe or ajax/xhr request I'm thinking you could loop through each image of the list refreshing the page to show a different image and check the cache against it's own modified date. So on this image's onload use serverside to decipher if it is not the last image when it is loaded go to the next image.
C.1a) This would mean that our list may need more information per image and I think the obvious one is the possible need of some server side script to adjust the headers as required by each image to minimize the footstep of re-caching changed site images.
My 2nd "suggestion" would be to notify the user of changes and direct them to clear their cache. (Carefully, remove only images and files when possible or warn them of data removal due to the process)
P.S. This is just an educated ideation. A quick theory. If/when I make it I will post the final. Probably not here because it will require server side scripting. This is at least a suggestion not mentioned in the OP's question that he say's he already tried.
It sounds like the base of your question is how to get the old version of the image out of the cache. I've had success just making a new call and specifying in the header not to pull from cache. You're just throwing this away once you fetch it, but the browser's cache should have the updated image at that point.
var headers = new Headers()
headers.append('pragma', 'no-cache')
headers.append('cache-control', 'no-cache')
var init = {
method: 'GET',
headers: headers,
mode: 'no-cors',
cache: 'no-cache',
}
fetch(new Request('path/to.file'), init)
However, it's important to recognize that this only affects the browser this is called from. If you want a new version of the file for any browser once the image is replaced, that will need to be accomplished via server configuration.
Here is a solution using the PHP function filemtime():
<?php
$addthis = filemtime('myimf.jpg');
?>
<img src="myimg.jpg?"<?= $addthis;?> >
Use the file modified time as a parameter will cause it to read from a cached version until the file has changed. This approach is better than using e.g. a random number as caching will still work if the file has not changed.
In the event that an image is re-uploaded, is there a way to CLEAR or REPLACE the previously cached image client-side? In my example above, the goal is to make the browser forget what "42.jpg" is
You're running firefox right?
Find the Tools Menu
Select Clear Private Data
Untick all the checkboxes except make sure Cache is Checked
Press OK
:-)
In all seriousness, I've never heard of such a thing existing, and I doubt there is an API for it. I can't imagine it'd be a good idea on part of browser developers to let you go poking around in their cache, and there's no motivation that I can see for them to ever implement such a feature.
I CANNOT use the META tag method OR the timestamp method, because I want all of the images cached under normal circumstances.
Why can't you use a timestamp (or etag, which amounts to the same thing)? Remember you should be using the timestamp of the image file itself, not just Time.Now.
I hate to be the bearer of bad news, but you don't have any other options.
If the images don't change, neither will the timestamp, so everything will be cached "under normal circumstances". If the images do change, they'll get a new timestamp (which they'll need to for caching reasons), but then that timestamp will remain valid forever until someone replaces the image again.
When changing the image filename is not an option then use a server side session variable and a javascript window.location.reload() function. As follows:
After Upload Complete:
Session("reload") = "yes"
On page_load:
If Session("reload") = "yes" Then
Session("reload") = Nothing
ClientScript.RegisterStartupScript(Me.GetType), "ReloadImages", "window.location.reload();", True)
End If
This allows the client browser to refresh only once because the session variable is reset after one occurance.
Hope this helps.
To replace cache for pictore you can store on server-side some version value and when you load picture just send this value instead timestamp. When your image will be changed change it`s version.
Try this code snippet:
var url = imgUrl? + Math.random();
This will make sure that each request is unique, so you will get the latest image always.
After much testing, the solution I have found in the following way.
1- I create a temporary folder to copy the images with the name adding time () .. (if the folder exists I delete content)
2- load the images from that temporary local folder
in this way I always make sure that the browser never caches images and works 100% correctly.
if (!is_dir(getcwd(). 'articulostemp')){
$oldmask = umask(0);mkdir(getcwd(). 'articulostemp', 0775);umask($oldmask);
}else{
rrmfiles(getcwd(). 'articulostemp');
}
foreach ($images as $image) {
$tmpname = time().'-'.$image;
$srcimage = getcwd().'articulos/'.$image;
$tmpimage = getcwd().'articulostemp/'.$tmpname;
copy($srcimage,$tmpimage);
$urlimage='articulostemp/'.$tmpname;
echo ' <img loading="lazy" src="'.$urlimage.'"/> ';
}
try below solutions,
myImg.src = "http://localhost/image.jpg?" + new Date().getTime();
Above solutions work for me :)
I usually do the same as #Greg told us, and I have a function for that:
function addMagicRefresh(url)
{
var symbol = url.indexOf('?') == -1 ? '?' : '&';
var magic = Math.random()*999999;
return url + symbol + 'magic=' + magic;
}
This will work since your server accepts it and you don't use the "magic" parameter any other way.
I hope it helps.
I have tried something ridiculously simple:
Go to FTP folder of the website and rename the IMG folder to IMG2. Refresh your website and you will see the images will be missing. Then rename the folder IMG2 back to IMG and it's done, at least it worked for me in Safari.

Categories