Question

I'm using JavaScript to create a basic graphic clock display on an HTML page. I'm updating digit graphics (each digit updated only when necessary) using the standard DOM mechanism:

digitOne.src = "file/path/one.png";

The clock works fine, but I want to know whether all or some browsers will mindlessly fetch the image from my site every time the src attribute is changed, rather than cache a copy in RAM. I'm worried that in some cases, perhaps in older browsers, viewing the graphic clock will create data traffic constantly and chew through my monthly data allowance.

So I'm hoping someone can tell me whether this is a risk, or point me to a mechanism to swap graphics in JavaScript which guarantees that an existing image will be used from memory rather than trigger a network fetch every time.

(I have hunted around for a definitive answer to this, but couldn't find one. I've not used JavaScript for DHTML since 1999/2000, so I'm a bit behind the times. At least it's no longer necessary to write two versions of every JavaScript function, one for IE4/5 and one for Netscape 4.)

Was it helpful?

Solution 2

I would recomend to you using HTML5 canvas 2D drawing. It not requires any images at all and is currently supported by all newer version of all browsers even in IE. Check this out

http://www.neilwallis.com/projects/html5/clock/index.php

Read this simple yet great tutorial:

http://diveintohtml5.info/canvas.html

OTHER TIPS

You don't have to worry about the traffic. It's easy to cache the images when initializing the application. Look into my example in the following JSFiddle: http://jsfiddle.net/pAwdC/. When I'm initializing the application I'm calling loadImages. This method creates img DOM element for each digit. It's src is being taken from the array imagesSrc. When the loadImages function is called the browser is making few HTTP get requests to the server:

enter image description here

Actually each request is made when:

current.src = imagesSrc[i];

is executed.

After the images are loaded, I'm just hiding them. When the images are with display: none or visibility: hidden the user cant actually see them but when you make these hidden elements visible no more requests are made, only eventual repaint, reflow/relayout, restyle are done by the browser. All elements are cached and displayed only when required. You can check your firebug or whatever other dev tool you're using that no more requests for these images are made.

Here is the code from my example:

var images = [],
    imagesSrc = ['https://lh3.ggpht.com/-107YXK-eAXs/UB6V49H9yuI/AAAAAAAACsY/69ceZJXaYZE/s1600/number-one-.png',
    'https://lh3.ggpht.com/-8rOrxAwDl48/Txf99Sus18I/AAAAAAAAL1w/VcmeP7rNFwY/s1600/number2c.png',
    'https://lh3.ggpht.com/-aGatHUidcGw/UG6Oh2HdWXI/AAAAAAAADQY/yc1CTC7cpOY/s1600/number3.png'];

function loadImages() {
    var current;
    for (var i = 0; i < imagesSrc.length; i += 1) {
        current = document.createElement('img');
        current.src = imagesSrc[i];
        images.push(current);
        current.style.display = 'none';
        document.body.appendChild(current);
    }
}

function showImage() {
    var current = showImage.current || 0;
    if (current >= 3) {
        current = 0;
    }
    hideImages();
    images[current].style.display = 'block';
    current += 1;
    showImage.current = current;
    setTimeout(function () {
        showImage();
    }, 1000);
}

function hideImages() {
    for (var i = 0; i < images.length; i += 1) {
        images[i].style.display = 'none';
    }
}

loadImages();
showImage();

For my example I need just a single instance of each digit. Of course for your clock you can create four instances (four img DOM elements) for each digit so that you can show duplicates.

For your application may be better approach will be to load the images on demand, but only once and then cache them. It's good to do this because the user may not stay on your page to see each digit (from 0 to 9) and you may improve a little your performance by this lazy loading. For this strategy you can check the flyweight pattern. It's main idea is to manage a set of reusable small objects and use them on demand, while controlling it's creation. Here is a UML class diagram which shows the structure of the pattern:

enter image description here

There are different variations of the approach I've mentioned. May be the most lightest variation you can do is to use a single image which contains all the digits. After that you can create different elements (for example div) with the size of a digit. When you set to these elements a background with specific position you can create all digits by loading only a single image. This will reduce your requests from 10 to just a single one. This approach is effectively used by facebook, for example.

If you need further assistance I'll be glad to help. ​

If CSS is enabled, the following pattern works. I'm presenting this one because it's a bit clearer than the solution if it's not.

<div id='clock'>
  <div id='digit0' style="display:block"><!-- ... --></div>
  <div id='digit1' style="display:none"><!-- ... --></div>
  <div id='digit2' style="display:none"><!-- ... --></div>
  <!-- ... -->
</div>

To change the digit display, hide the currently visible digit and make visible the next one. The JavaScript-only solution is related. Make a single invisible <div> to hide the invisible digits. Add and remove individual digit <div> elements, swapping the old digit from the clock display with the next digit from the digit storehouse element.

Both these solutions have the behavior that images within the DOM subtrees are only fetched once, because the subtrees are never deleted.

If you want to be absolutely sure, you could generate the HTML element with the image of the digit and place it to the page with display: none, so it's already loaded and on the page.

If the digit is being needed, you first check for the HTML element on the page and take this one, set it to display: block or whatever you need and replace the current digit element with that one.

As some sample code, I've just put this together.

var digit_images = ["file/path/one.png", "file/path/two.png", "file/path/three.png", ...];

function giveMeTheDigit(digit)
{
    var img = digit_images[digit];
    var element = $("#digit_holder" + digit);

    if (element.length == 1)
    {
        $(".digit_holder").hide(); //hide the current holder
        element.show(); //show the new one
    }
    else
    {
        $('<div class="digit_holder" id="digit_holder' + digit + '"><img src="' + img + '" /></div>')
            .appendTo("#yourDestination");
    }
}

This code is not tested, but I think you know what I'm after and could edit this to your needs. Good luck!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top