8

I have an ashx file handler that generates my images.

<img src="www.mywebsite.com/action/getimage.ashx?imageID=f8be4bf6&width=100&height=700&bgcolor=999" />

This all works fine.

Now, I want to use lazy loading. Using this jquery lazy loading plugin

So i adjusted my html images like this:

<img src="imageplaceholder.gif" original-data="www.mywebsite.com/action/getimage.ashx?imageID=f8be4bf6&width=100&height=700&bgcolor=999" />

And added the following script:

$(function() {
   $("img").lazyload();
});

I noticed in the network tab of google chrome devoloper tools that there are two calls made to this filehandler.

I've created a testing fiddle here: link If you scroll down on this fiddle you'll see two image requests when the image is loaded in Google Chrome. In Firefox and IE this works with only one call.

Is there any way to avoid this behavior?

UPDATE:

The following headers are set in the file handler:

[0] "Server"    "Microsoft-IIS/7.5"
[1] "Set-Cookie"    "lang=nl; expires=Tue, 04-Feb-2014 13:08:56 GMT; path=/"

And the Expires property of the Response object is:

context.Response.Expires = 0
ThdK
  • 9,916
  • 23
  • 74
  • 101
  • Can you also post the contents of `ProcessRequest` of the image handler? The reason for this is because the behavior occurs only if the `data-original` uses the image handler (`www.mywebsite.com/action/getimage.ashx?imageID=f8be4bf6&width=100&height=700&bgcolor=999`) but when its a static image like `http://www.appelsiini.net/attachments/jquery.png` then there is just one call. – Andy Refuerzo Jan 30 '13 at 12:11
  • I've noticed that too. Static Images works fine. The file handler used in the example fiddle is not the file handler used in my own sollution. I tried different file handlers i found on the web to see if the problem was not my code. So far, they all had the same issue. So I don't think the problem will be with the image handler itself. – ThdK Jan 31 '13 at 08:46

3 Answers3

10

I believe the root issue is that Chrome isn't caching the image. In this demo, Chrome will issue a new request every time you click the button.

The lazy load script triggers 2 requests because it first (pre)loads the image into a private img element, then it assigns the image URL to the original img element.

I suggest adding an Expires or Cache-Control header, and a Last-Modified or ETag header, to the response from your image handler so that Chrome will cache the image. (For more on caching, see the Caching Tutorial for Web Authors and Webmasters.)


Update: I suggest adding something like this to your image handler (from MSDN):

Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetValidUntilExpires(true);
Jeffery To
  • 11,836
  • 1
  • 27
  • 42
  • If it (pre)loads the image then wouldn't that defeat the purpose of (lazy)loading? – Andy Refuerzo Feb 04 '13 at 13:11
  • The 'pre' load only happens when the image is actually visible. I don't know how the lazy load plugins really works, but i can tell that both the first call and the second call are made when the image becomes inside the viewport. I've updated my question with a the current caching headers of the response in my image handler. – ThdK Feb 04 '13 at 13:23
  • @ThdK Actually your comment highlights my answer that Chrome handles `$("img").attr("src", "")` differently. If you look in the code of the plugin, `line 110` and `line 115` are the only places where the `src` attribute's value is set to the image handler's url. In my tests, when these lines are executed, a request is fired for the image. The only difference is that before `line 110`, the `` gets hidden. – Andy Refuerzo Feb 04 '13 at 13:58
  • Please see my update - `context.Response.Expires = 0` would mean the image can be cached for 0 minutes – Jeffery To Feb 04 '13 at 15:16
5

When something like this happens, make sure you don't have Chrome DevTools opened and "Disable cache" checkbox ticked. If any addon, setting or anything else causes cache to be disabled, same thing might happen.

Mark
  • 1,357
  • 16
  • 30
  • 2
    This is actually what is causing this issue for me. Thank you for making me check that! Unchecking "Disable cache" in dev tools makes it all work normally and it is unrelated to the plugin - will happen with any kind of lazy loading lib (in my case inside React) – easwee May 09 '19 at 12:06
3

It seems that Google Chrome handles $("img").attr("src", "") differently than other browsers.

Looking at the source code of the plugin on GitHub, and adding a break point in Chrome (going step by step), the calls to the image handler occurs when it modifies the src attribute of the image to the value of original-data.

While it is possible that the image handler is the problem (as I commented before), the solution that I found was to change line 115 of the plugin's source from

.attr("src", $self.data(settings.data_attribute));

to

.attr("src", "data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==");

the new value is a base64 encoded string for a 1px by 1px transparent GIF image.

In your test fiddle, find in the minified version the 2nd occurrence of

c.data(h.data_attribute)

and change it to

"data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="

It will still call twice but the first call will be negligible (0kb?) and other browsers are not affected by this change.

Andy Refuerzo
  • 3,312
  • 1
  • 31
  • 38
  • Why has this answer been downvoted? I've made your change in the plugin and then i see indeed the second call is made only for the 1x1px. I'll discuss this option with someone else here to see if that's something we can do. I'm not a jquery expert so i can't really find out why that line of code really does and if it's 100% safe to change it. So if anyone of you has other opinion on this. Please let me know! Thanks a lot already for spending your time on this one! – ThdK Feb 01 '13 at 08:41
  • I am also baffled as to why Chrome behaves like this for this plugin but my line of thinking was that we can't change the behavior of the browser and we can't change the image handler so we're left only with the plugin. I'm no jQuery expert as well so if you get a conclusive answer for this behavior, please do post it here too. :) – Andy Refuerzo Feb 01 '13 at 09:44
  • As for the downvote, I have no idea why. I think this is the best solution to avoid requesting the same image twice in Chrome, unless you'd want to change your lazy loader plugin (don't ask me what replacement - I don't use any). – Andy Refuerzo Feb 01 '13 at 09:47
  • @ThdK It was probably downvoted because the suggested fix requires editing a plugin, it is a dirty fix. For example, if the plugin was being retrieved from a CDN then this would not be possible. Just an idea. I would upvote this answer due to the effort that Andy has put in to try and solve this for you, but I do not see this as the actual solution. ***continued*** – Ben Carey Feb 04 '13 at 08:29
  • @ThdK I believe that the issue actually lies in the script that retrieves the image. This is demonstrated in my answer. However, I appreciate that there may be an issue with the way Chrome handles the data attribute, and resultantly, my answer may not be suitable. – Ben Carey Feb 04 '13 at 08:29
  • I've upvoted the answers because i appreciate your time. My script is called twice in chrome, my script is only run after this call on the server. So i think we have to look why this second request is made. Whatever the code in the script my look like. Could there be a problem with caching headers? – ThdK Feb 04 '13 at 08:48
  • @BenCarey I tested the behavior with other image handlers (having .ashx extensions) and got the same results. I don't consider that it is a dirty fix since the plugin is an open source project. :) Has it ever crossed your mind that what we're encountering is a bug specific only to the plugin and chrome when using asp.net image handlers? Another imagehandler that I tested, found on the web: `http://www.recoding.it/Demos/imghandler.ashx?i=~%2fImages%2fphoto_1.jpg&w=220&h=0&pt=Scale&va=Middle&ha=Center&di=&wpath=&wpos=bottom_right&ch=False&cr=0&flip=None&ie=None&rot=Rotate0` – Andy Refuerzo Feb 04 '13 at 13:06
  • @AndyRefuerzo In that case you are right in the sense that it is not to do with the script providing the image. Resultantly, I will remove my answer. It could well be a bug, albeit a very weird bug!! – Ben Carey Feb 04 '13 at 13:32