开发者

how can I use javascript or php to determine when images are loaded if image tags are dynamically created from database?

I have a page that's very image-intensive. This is by client request - it's a list of merchants with a logo for each one. The list is quite long (over 500), and yes - the client insists on displaying all of them. We do have an ajax typeahead search to help users find what they're looking for without scrolling, so it's not a total disaster.

Here's the issue: the client is just now realizing that it takes a long time to load this page because of 开发者_开发技巧all the logos. Even if each one is only a few kb, it still adds up pretty quickly. He's now decided he wants a progress bar to display while the images are loading. I've never done that before, so I starting looking around, and most of the ones I've seen rely on getting an array of img tags and looping through to check the complete property. The problem I'm having (at least I think this is what's causing the problem) is that the image tags are generated by a database query, and I think the javascript to get the image array is loading before the image tags are finished loading. Obviously this isn't an issue on pages where the images are hard-coded.

Can anyone point me in the right direction of how I can implement a progress bar on img tags that get loaded dynamically? My site is written in PHP, so I'm perfectly happy to do something server-side if that would work better.


As pretty much everyone here has noted, this is a nasty problem to have to solve. Accordingly, I propose sidestepping the technical components of it and addressing only the human ones.

Leave everything almost exactly as it is. All you have to do is find or make a throbber (I use http://ajaxload.info/ and it couldn't be easier), and use it as the background image for a CSS selector that only applies to the logos on the page.

Users (and clients who make unreasonable requests!) are far more frustrated by a lack of responsiveness than they are by things taking time. This quick gimmicky fix might be just enough to coax site users to perceive the problem more as the latter than as the former.


CSS Sprites will definitely be a good start in your case. If you got 500 spearate images on one page, then browser will have to start 500 new connections to fetch them, and unfortunately, concurrent connections will be around 20 or something, so... it is not good.

CSS Sprites from css-tricks.com


I'd suggest pre-making and caching of the logos (or their various states), as your own hunch is that the main bottleneck is that "the image tags are generated by a database query". Is this at all possible?

It's better to store a few states or whatever with a naming scheme that makes it possible to fetch the right image, than regenerating them on-the-fly each time. Of course, you'll need a proper cache handling mechanism, so it's not like an easy task, but more often than not, your hunch is helping you in the right direction.

If you're able to boil it down to a few static files per logo, you could also consider using a CDN and/or multiple subdomains, as Michael Mao suggests.


I haven't tested this but something like this might work (its jQuery)

<?php // Do your select image stuff from here ?>
<html>
<head></head>
<body>
<script type="text/javascript">
$(document).ready(function () {
    var images = <?php echo json_encode($images); ?>;
    $.each(images, function(i, image) {
        $(new Image()).load(function () {
            $('body').append(this);
            alert('Loaded '+i+' out of '+images.length);
        }).attr('src', image);
    })
});
</script>


Since you already have a javascript search to get people to specific listings faster, how about loading a placeholder static image for all logos and then replacing the placeholder with the correct logos on an as-needed basis? "As-needed" could be determined by JavasScript calculation of window position and any typed input.

Do your just-in-time image loading from multiple subdomain masks to parallelize requests and you should be able to pop the images up somewhat quickly as-needed without bogging down the page by loading unnecessary images.

It's not pretty, but neither is the client's request.

Edit: As far as a progress bar goes, when you determine a window location (or typed-input location), determine how many listings will be in-view, and how many listings to buffer above and below the view. Then you'll have a total number of listings and you can update a JavaScript/HTML progressbar as you dynamically replace the logos within that range.


It would be much easier to answer the question if I could see the complete code but I can remember doing something remotely similar and I ended up using a custom JavaScript object. You could perhaps start with an object like this somewhere in the head of your app:

function Iterator() {

  var counter = 0;  
  this.images = 215; // This number comes from the DB and gives you a total number of images
  this.progress = counter / this.images

  this.hasMore = function() { counter < this.images }

  this.getPicture = function() {
    // send a request to the server using counter as a parameter
    // upon receiving this request the server should load only ONE image (LIMIT=1 in SQL)
    // with OFFSET equal to the value of "counter"
    // when the image loads (use whatever JS framework you need for that), 
    // we increment the counter:
    counter++;
  }

  this.loadPictures = function() {
    while this.hasMore() {
      this.getPicture()
      // You can do something with the "progress" attribute here, to be visualizad by your progress bar
    }
  }

);

You sure need to instantiate the Iterator object on body load and have it execute the "loadPictures" function.

Please let me know if you have any problems implementing that.


Here's a javascript-only solution that shouldn't require any modification to your server-side code. Using jquery:

$(document).ready(function() {
    var loadedSoFar = 0;
    //use jquery to get all image tags you want.
    //The totalImgs is used to calculate percent and is the length of the jquery array
    var totalImgs = $("#imgHolder img").each(function(i, img) {
        //if this image has already loaded, add it to loadedSoFar.
        if (img.complete)
            loadedSoFar++;
        else {
            //otherwise add a load event for the image.
            $(img).load(function() {
                loadedSoFar++;
                console.log("complete: " + (loadedSoFar / totalImgs * 100) + "%");
            });
        }
    }).length;
});

I wrote this assuming all the images are already in the dom when the document.ready is called. If it is not, move this to a function and call it after the img tags are loaded into the dom from the server (via ajax request for instance).

Basically all it does is find all the imgs in imgHolder (modify the selector to match your situation), and wire the load event so it can update the loadedSoFar count. If the image has already loaded by the time this script runs, the load event would never fire, so increment the loadedSoFar counter right away. The number of total images that need to be loaded will be the length of the jquery object array returned by the selector.

I'll leave it to you to write a progress bar, but I do recommend this plugin: http://t.wits.sg/jquery-progress-bar/


I'd definitely try to avoid the progress bar -- you're going to really struggle with it.

If you really must do it, probably the best you can hope for is to fake it - ie have it show progress on a given amount of time, which you'd set as an approximation of the actual time it takes to load the page. Not foolproof but far easier than trying to actually time the loading progress.

Don't forget also that the progress bar itself will add to the loading time. And you'll need to have the code for it embedded in your actual HTML code; if it's in an external javascript file it could itself be subject to loading delays, which would make the whole excersise pointless.

So as I say, it's probably not worth the effort. What would be worth the effort would be to try to reduce the loading time. If it's noticable enough that you're considering a progress bar then there's something seriously wrong.

There are a whole stack to techniques for speeding up site loading times; it's a whole topic on its own. But I'll try to give you a few pointers. I suggest you also take some time googling for additional and follow-up information, though.

  • Image optimisation. If you haven't done so already, run all your images through an optimising program. You may find that you can reduce file sizes and thus load-times significantly.

  • CSS Sprites. One of the main causes of slow loading times is having too many separate HTTP requests. Since a browser can only load a given number of files at once, any files over that number will have to wait till others have finished before they can even begin loading. CSS sprites solves this by combining a number of images into a single file and using CSS to display only the relevant part of it in each spot. This is typically used for groups of related images.

  • Lazy Load. There is a jQuery plugin called LazyLoad which tells your page to load images only as they are needed. Images that are off the bottom of the viewable page are deferred until the user starts scrolling the page. This means that the images that are visible immediately are loaded first, making the page as a whole appear to load more quickly.

That'll do for now. There's loads more, of course, but all I'm really trying to say is: Optimise to get rid of the speed issue rather than trying to cobble together a band aid solution.

Hope that helps.


there are different ways to speedup image loading especially when you have a lot of them

  • Sprite - Use sprite where you group a number of images together and use the css background property (FACT: one big image better speed than multiple requested images).
  • Use the <image/> tag properly. You can add the lowsrc="" attribute to show a low resolution image until the real image aka src="" attribute is fully loaded
  • Use the ajax, although you may have 500+ images users will never see the full list. So you can load 6 at a time (or Nth at a time) when the document is fully loaded you can add the rest that way u can speed up the loading time as the user will only see some images and by the time they click next set of images they would have been loaded (or wait less) better yet to save broadband only use the ajax when required aka only when they click next or scroll down auto load new images. (look at google images and ajax used while scralling)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜