How to Cache an Image in JavaScript

How do you cache an image in Javascript

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 = [];
}
var list = preloadImages.list;
for (var i = 0; i < array.length; i++) {
var img = new Image();
img.onload = function() {
var index = list.indexOf(this);
if (index !== -1) {
// remove image from the array once it's loaded
// for memory consumption reasons
list.splice(index, 1);
}
}
list.push(img);
img.src = array[i];
}
}

preloadImages(["url1.jpg", "url2.jpg", "url3.jpg"]);

This function can be called as many times as you want and each time, it will just add more images to the precache.

Once images have 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.

Eventually over time, the browser cache may fill up and toss the oldest things that haven't been used in awhile. So eventually, the images will get flushed out of the cache, but they should stay there for awhile (depending upon how large the cache is and how much other browsing is done). Everytime the images are actually preloaded again or used in a web page, it refreshes their position in the browser cache automatically so they are less likely to get flushed out of the cache.

The browser cache is cross-page so it works for any page loaded into the browser. So you can precache in one place in your site and the browser cache will then work for all the other pages on your site.


When precaching as above, the images are loaded asynchronously so they will not block the loading or display of your page. But, if your page has lots of images of its own, these precache images can compete for bandwidth or connections with the images that are displayed in your page. Normally, this isn't a noticeable issue, but on a slow connection, this precaching could slow down the loading of the main page. If it was OK for preload images to be loaded last, then you could use a version of the function that would wait to start the preloading until after all other page resources were already loaded.

function preloadImages(array, waitForOtherResources, timeout) {
var loaded = false, list = preloadImages.list, imgs = array.slice(0), t = timeout || 15*1000, timer;
if (!preloadImages.list) {
preloadImages.list = [];
}
if (!waitForOtherResources || document.readyState === 'complete') {
loadNow();
} else {
window.addEventListener("load", function() {
clearTimeout(timer);
loadNow();
});
// in case window.addEventListener doesn't get called (sometimes some resource gets stuck)
// then preload the images anyway after some timeout time
timer = setTimeout(loadNow, t);
}

function loadNow() {
if (!loaded) {
loaded = true;
for (var i = 0; i < imgs.length; i++) {
var img = new Image();
img.onload = img.onerror = img.onabort = function() {
var index = list.indexOf(this);
if (index !== -1) {
// remove image from the array once it's loaded
// for memory consumption reasons
list.splice(index, 1);
}
}
list.push(img);
img.src = imgs[i];
}
}
}
}

preloadImages(["url1.jpg", "url2.jpg", "url3.jpg"], true);
preloadImages(["url99.jpg", "url98.jpg"], true);

How do I pre-cache images for quick viewing with javascript?

You don't need to create any page elements, it can all be preloaded using JavaScript:

tempImg = new Image()
tempImg.src="pic2.jpg"

EDIT:

If you have a lot of images, you can use the poor-man's multi-preloader:

preloads = "red.gif,green.gif,blue.gif".split(",")
var tempImg = []

for(var x=0;x<preloads.length;x++) {
tempImg[x] = new Image()
tempImg[x].src = preloads[x]
}

Force image caching with javascript

You can't change the image server if it isn't yours, but you can trivially write something on your own server to handle it for you.

First write something in your server-side language of choice (PHP, ASP.NET, whatever) that:

  1. Hits http://a.random-image.net/handler.aspx?username=chaosdragon&randomizername=goat&random=292.3402&fromrandomrandomizer=yes and downloads it. You generate a key in one of two way. Either get a hash of the whole thing (MD5 should be fine, it's not a security-related use so worries that it's too weak these days don't apply). Or get the size of the image - the latter could have a few duplicates, but is faster to produce.
  2. If the image isn't already stored, save it in a location using that key as part of its filename, and the content-type as another part (in case there's a mixture of JPEGs and PNGs)
  3. Respond with an XML or JSON response with the URI for the next stage.

In your client side-code, you hit that URI through XmlHttpRequest to obtain the URI to use with your images. If you want a new random one, hit that first URI again, if you want the same image for two or more places, use the same result.

That URI hits something like http://yourserver/storedRandImage?id=XXX where XXX is the key (hash or size as decided above). The handler for that looks up the stored copies of the images, and sends the file down the response stream, with the correct content-type.

This is all really easy technically, but the possible issue is a legal one, since you're storing copies of the images on another server, you may no longer be within the terms of your agreement with the service sending the random images.

can we push images to browser cache using javascript

This can be done purely in JavaScript by using the Image object.

var cachedImage = new Image();
cachedImage.addEventListener('load', function () {
alert('Cached image loaded');
});
cachedImage.src = 'http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png';

I have created a working JSFIDDLE example showing this at http://jsfiddle.net/pwdst/wc1zrL0v/

The new images could be created in response to a user event, for example clicking on a button, or even scrolling past a certain position. If the image from the server has the proper cache headers, it will then be retained in the browser cache for later use in your print page.

You will be able to see the request in the "Network" tab of the Chrome dev tools, or by using the excellent Fiddler tool from Telerik. Successful load will also trigger the load event listener added in the code sample.

Is there a way to load images to user's cache asynchronously?

You can preload images like this:

function preloadImages(srcs) {
if (!preloadImages.cache) {
preloadImages.cache = [];
}
var img;
for (var i = 0; i < srcs.length; i++) {
img = new Image();
img.src = srcs[i];
preloadImages.cache.push(img);
}
}

// then to call it, you would use this
var imageSrcs = ["src1", "src2", "src3", "src4"];

preloadImages(imageSrcs);

Just fill in the URLs in the imageSrcs array and run this when your page first runs. The sooner you run it, the earlier your images will be available.

FYI, a related answer here: Image preloader javascript that supports events.

How to cache image rasterized

Ref comments - there is a way to pre-cache video frames. Each frame will use a full memory block for the bitmap (which in any case also is the case with preloaded image sequences).

Cache Process

  • Create an "off-line" video element
  • Set video source with preload set to auto
  • You need to know the frame rate (typical: 30 fps for USA/Japan, 25 fps for Europe), calculate a time delta based on this, ie. 1 / FPS.
  • Use the timeupdate event for every currentTime update as setting current time is asynchronous.

Chose an in-point in the video, cache (this can take a while due to the event cycle), store to a frame buffer using a canvas element for each frame. Then playback the buffer when and as needed (this also gives you the ability to play video backwards as shown below, a feature not yet supported in the browsers).

Example

This example will load a video from net, cache 90 (3 sec @ 30 fps) frames to memory, then play back the sequence ping-pong in the window (the images you see are from the cache obviously):

var canvas = document.querySelector("canvas"),    ctx = canvas.getContext("2d"),    video = document.createElement("video"),    frames = [],    w = canvas.width, h = canvas.height;
video.addEventListener("canplay", cache);video.preload = "auto";video.src = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4";
function cache() { this.removeEventListener("canplay", cache); // remove to avoid recalls
var fps = 30, // assuming 30 FPS delta = 1 / fps, // time delta count = 0, // current cached frame max = fps * 3, // 3 seconds div = document.querySelector("div"); // just for info
this.addEventListener("timeupdate", cacheFrame); // time update is aync this.currentTime = 19; // start with initial time function cacheFrame() { div.innerHTML = "Caching frame: " + count; if (count++ < max) { // create canvas for frame-buffer; var canvas = document.createElement("canvas"), ctx = canvas.getContext("2d");
canvas.width = this.videoWidth; // canvas size = video frame canvas.height = this.videoHeight; ctx.drawImage(video, 0, 0); // draw current frame frames.push(canvas); // store frame this.currentTime += delta; // update time, wait.. } else { this.removeEventListener("timeupdate", cacheFrame); // remove!! play(); // play back cached sequence } }}
// to demo the cached framesfunction play() { var current = 0, max = frames.length, dlt = 1, div = document.querySelector("div"), toggle = false, mem = max * video.videoWidth * video.videoHeight * 4; // always RGBA mem = (mem / 1024) / 1024; //mb
ctx.fillStyle = "red";
(function loop() { toggle = !toggle; // toggle FPS to 30 FPS requestAnimationFrame(loop); if (toggle) { div.innerHTML = "Playing frame: " + current + " (raw mem: " + mem.toFixed(1) + " mb)";
ctx.drawImage(frames[current], 0, 0, w, h); // using frame-buffer ctx.fillRect(0, 0, current/max * w, 3); current += dlt; if (!current || current === max-1) dlt = -dlt; // pong-pong } })();}
html, body {width:100%;height:100%}body {margin:0; overflow:hidden;background:#aaa}div {font:bold 20px monospace;padding:12px;color:#000}canvas {z-index:-1;position:fixed;left:0;top:0;width:100%;height:100%;min-height:400px}
<div>Pre-loading video... wait for it, wait for it...</div><canvas width=600 height=360></canvas>


Related Topics



Leave a reply



Submit