Get faster page loading with on-demand thumbnail image retrieval

Get faster page loading with on-demand thumbnail image retrieval

By | 2016-12-01T16:37:39+00:00 November 13th, 2015|Tips & Tricks|2 Comments

We recently had a customer concerned about performance when viewing certain albums in their gallery. After investigation, we saw that these albums had a large number of media assets. In one case there were 4,120 images. Since each thumbnail image required an HTTP call to the server, that album had at least 4,120 calls to the server before the page was fully loaded. In Chrome that took about 20 seconds. In Microsoft Edge it was dramatically better, about 5 seconds. But in either case that’s too much time.

Our best practice advice is to try to keep fewer than 500 or 1000 items in each album, but this customer had business requirements that made splitting up the album impossible. They turned on the paging feature, which helped speed up the screen rendering but under the hood those 4,120 HTTP calls were still getting made, triggering the spinning circle icon we’ve all seen that tells you a page is loading resources.

I came up with a solution that delayed the thumbnail image loading until the page containing that image was visible. So if you have an album with 1000 images and you have paging enabled with a page size of 25, loading the album will only trigger 25 HTTP calls (not counting the normal ones associated with the rest of the page resources like CSS and JS files). When you navigate to the next page, the gallery will issue another 25 HTTP calls for those thumbnail images, and so on.

This made the client very happy, with pages now loading in a second or so. I believe we’ll incorporate this enhancement in the next version, but I thought I’d share the tweak with you now so you can apply it to your 3.2.1 gallery if you want. First I’ll give you the quick and dirty instructions for applying the trick to your gallery, then I’ll dig under the hood to show you what JavaScript was modified to accomplish this.

How to implement delayed thumbnail loading in your gallery

  1. Download the JavaScript patch file for delayed thumbnail loading in Gallery Server 3.2.1.

  2. Enable paging on the Albums – General page in the Site Admin area.

    Album paging

  3. Replace src='{{:Views

    [ViewIndex].Url}}’  with srcDelay='{{:Views[ViewIndex].Url}}’  in the Album UI template.

    Replace the src attribute with srcDelay

  4. Replace gs\script\gallery.min.js with the one from the patch you downloaded in step 1.

    The gallery.min.js JavaScript file

  5. (Optional) Replace gs\script\debug\gallery.js with the one in the patch. This is needed only if you ever set debug=”true” in web.config for debugging purposes.

That’s it. The thumbnail images are now loaded only when you navigate to the page containing them. You can prove this to yourself by looking at the network traffic in your browser developer tools (usually activated with F12).

TIP: Since you can’t edit the default UI template, you must make a copy and edit that one. But when you do, be sure you do two things: (1) Activate the copied template by selecting the target albums. (2) De-activate the original, default template by unchecking the target albums.

Under the hood

Let’s look at why there is a performance issue in the first place. When paging is enabled, Gallery Server only renders the HTML for the current page to the screen. So if paging is set to 25 items, then HTML for only 25 thumbnails images is added to a parent DOM element in the page and shown in the browser.

So why, then, does the browser issue HTTP calls for all thumbnail images in the album? It’s because of this line in the renderPager() function in gallery.js:

var $albumHtml = $(albumHtml);

albumHtml is a string variable containing the HTML for the entire album as generated from the album UI template. Even when paging is enabled this string contains the HTML for all thumbnails in the album. The line takes this HTML string and asks jQuery to turn it into a set of DOM elements. As soon as an HTML string for an img tag is turned into a DOM element, the browser issues an HTTP request for the src attribute. This happens even when the DOM element exists only as a variable and hasn’t been added to the page.

My first thought when I saw this was to just leave it as an HTML string and convert only the current page’s worth of HTML into DOM elements for adding to the page. But this meant coming up with a way to parse the string to retrieve the slice of HTML needed for the current page, and this is not an easy task, especially considering how easy it is to do once that string has been turned into DOM elements:

var $albumHtmlThmbs = $albumHtml.find('.thmb').clone();
var html = $albumHtmlThmbs.slice(visibleIndices[0], visibleIndices[1]);

So I had another idea. Since it is the src attribute of image tags that triggers the get requests, what if the src attribute was renamed something else, like srcDelay? Browsers ignore attributes they don’t recognize, so no request is made. Then, as the user navigates back and forth between pages in the album, we rename the attribute back to src, which finally triggers the browser into retrieving the thumbnail image.

This ended up being the final solution and is the one described above. We start by editing the Album UI template and changing the src attribute of thumbnail images to srcDelay. You can use any name you want, but it must match the name you use in JavaScript that seeks it out for replacement.

Then we make a few changes to the gallery.js JavaScript file. Add a function to perform the attribute replacement. I put it just before the renderPager function:

var activateImages = function (html) {
 $('img.gsp_thmb_img', html).each(function () {
  if (this.getAttribute('srcDelay')) {
   this.setAttribute('src', this.getAttribute('srcDelay'));
   this.removeAttribute('srcDelay');
  }
 });
}

Then we need to call it from two places – inside the pager rendering and – just in case paging is disabled – from the non-pager rendering section. Look for this code in gallery.js:

var html = $albumHtmlThmbs.slice(visibleIndices[0], visibleIndices[1]);
$('.gsp_abm_thmbs').append(html.hide().fadeIn());

Insert a call to activateImages like so:

var html = $albumHtmlThmbs.slice(visibleIndices[0], visibleIndices[1]);
activateImages(html);
$('.gsp_abm_thmbs').append(html.hide().fadeIn());

To update the second location, look for this code:

if (!renderPager(albumHtml)) {
 self.html(albumHtml); // Render HTML template and add to page
 configThmbs(); // Assign width & height of thumbnails, make selectable
}

And change it to this:

if (!renderPager(albumHtml)) {
 var $albumHtml = $(albumHtml);
 activateImages($albumHtml);
 self.html($albumHtml);
 configThmbs(); // Assign width & height of thumbnails, make selectable
}

This is all you need to change to implement the solution while in debug mode (debug=”true” in web.config). But the minified version of this file – gallery.min.js – is used for production mode (debug=”false” in web.config). Use the minifier of your choice or just grab the minified one I posted earlier.

Share this story

About the Author:

Founder and Lead Developer of Gallery Server

2 Comments

  1. john.mcculloch December 27, 2015 at 3:42 am

    Hi – I tried this but unfortunately following de-activating the default UI and activating the newly copied UI (which I called “Delayed”), all I got were blank white thumbnails. Going back to “default” made them re-appear again. Tried re-starting the website but to no avail. My only slightly unusual config is that I have images, compressed and thumbs in different directories – could this be the cause? Thanks John

  2. Roger Martin December 28, 2015 at 8:35 am

    John – In the future please use the support forum. I know others have implemented this based the instructions in this post, so the first thing I would do is carefully review the instructions to make sure you haven’t missed any steps or made a typo. If you can’t find anything then you need to do some standard JavaScript troubleshooting to figure out where the root cause is.

Leave A Comment

You must be logged in to post a comment.