views:

68

answers:

3

If I have an img tag like

<img src="example.png" />

and I set it via

myImg.src = "example.png";

to the same value again, will this be a no-op, or will browsers unnecessarily redraw the image? (I'm mainly interested in the behaviour of IE6-8, FF3.x, Safari 4-5 and Chrome.)

I need to change many (hundreds of) images at once, and manually comparing the src attribute might be a little bit superfluous - as I assume, that the browser already does this for me?

+2  A: 

When you change a bunch of elements at once, you're usually blocking the UI thread anyway, so only one redraw after the JavaScript completes is happening, meaning the per-image redraw really isn't a factor.

I wouldn't double check anything here, let the browser take care of it, the new ones are smart enough to do this in an efficient way (and it's never really been that much of a problem anyway).

The case you'll see here is new images loading and re-flowing the page as they load, that's what's expensive here, existing images are very minor compared to this cost.

Nick Craver
@Marcel - Nope..."dp" should have been "load", not really sure how I FUBARed that one...thanks for the catch though!
Nick Craver
+2  A: 

Don't assume the browser will do it for you. I am working on a project of similar scale which requires hundreds of (dynamic-loading) images, with speed as the top priority.

Caching the 'src' property of every element is highly recommended. It is expensive to read and set hundreds of DOM element properties, and even setting src to the same value may cause reflow or paint events.

[Edit] The majority of sluggishness in the interface was due to all my loops and processes. Once those were optimized, the UI was very snappy, even when continuously loading hundreds of images.

[Edit 2] In light of your additional information (the images are all small status icons), perhaps you should consider simply declaring a class for each status in your CSS. Also, you might want to look into using cloneNode and replaceNode for a very quick and efficient swap.

[Edit 3] Try absolutely-positioning your image elements. It will limit the amount of reflow that needs to happen, since absolutely-positioned elements are outside of the flow.

Tim
To be more precise: it is expensive to access hundreds of **DOM elements** in JavaScript, that's still the bottle-neck of many programs.
Marcel Korpel
Very true; I have updated the answer.
Tim
@Tim: Thanks, very interesting! I have thought about caching the src property (or in my case: using an integer to remember the state) - I'd prefer to avoid it (it's additional complexity), but if it's true that setting the src to an unchanged value can cause a **reflow**, then I'll definitely do it. Are you sure about the reflow?
Chris Lercher
@chris_l - It can't cause any more reflow than normal, not if you're doing it in a batch...as I mention in the other answer, you're locking up the UI thread until the script's done anyway, so only one reflow with the images you have in cache will happen...the others still getting loaded will also cause a reflow if they don't have dimensions, not much you can do about that other than give them dimensions.
Nick Craver
@Nick: I'm already using dimensions. Since the images are in different elements (divs), I worry, that they may cause separate reflows within each div (?) I don't know very much about browser reflow strategies, so this is just an assumption.
Chris Lercher
@chris_l - If they have dimensions they won't cause a reflow...a reflow happens because it renders without knowing dimensions, then then the image loads the page resizes to accommodate it (since it now knows the dimensions)...if it has the dimensions from the start, there's no reflow needed.
Nick Craver
I'm pretty sure it can trigger reflow, but as Nick says, it might not matter. But as Marcel and I (indirectly in the edit) said, reflow isn't the only thing you have to worry about.
Tim
@Tim: Very good point again - I didn't think about the absolute positioning. My images are already positioned absolutely in their DIV. So all that's left is a plain redraw. This would increase the redraw box of the window a little bit, but I believe that this cost will be smaller than the cost of setting the DOM attribute. Your answers (and Nick's and Marcel's) have helped me a lot. Now all I'll have to do is evaluating the cost between keeping a state variable and setting a DOM attribute. I'll figure that out. Thanks!
Chris Lercher
+2  A: 

I recommend using CSS Sprite technique. More info at: http://www.alistapart.com/articles/

You can use an image that contains all the icons. Then instead of changing the src attribute, you update the background property.

Zafer
@Zafer: Thanks for the suggestion. I'm afraid I can't use that, because background-images don't scale when the user does a text-resize (the images must always have exactly 1em height). Background images can't be scaled in any way (with CSS 2.1).
Chris Lercher
@chris – Not true, at least not in Firefox 3.6.8; the arrow images on this page *are* background images and they do scale when zooming in and out.
Marcel Korpel
@Marcel: A page zoom zooms everything of course. But check the option "View -> Zoom -> Zoom Text Only". Some users have that option checked (and for some browsers it's the default.)
Chris Lercher
@chris – In that case, normal images (like the gravatars) aren't zoomed as well.
Marcel Korpel
@Marcel: You can have them scaling, if you specify the size in em.
Chris Lercher
@chris: if the zoom event can be detected, you can change the background image accordingly. There is a way to detect the event: http://stackoverflow.com/questions/995914/catch-browsers-zoom-event-in-javascriptSo, for different zoom levels there can be different background images. But this time, you need to recalculate and apply new bg-x and y values to span elements.
Zafer