1

I have one page with too much images that are divided unequally into divs which classes are photossetc. The main div that holds all the divs has an id of infscroll. At the beginning every div visibility is hidden and position is absolute and every div has an attribute named myflagc which value is "notok".

I don't want to wait for all the images in the page to load to show the divs therefore binding load to window is not an option, instead I want to show every div which content loaded independently.

Here is the jQuery/JavasScript code I made:

function imagesloaded(){

    var infscrolllength=jQuery('#infscroll').find('.photossetc').length;
    // gets the numbers of divs
    var completedsts = 0;
    // variable for the number of divs that completed loading (set to 0)

        jQuery('#infscroll .photossetc').each(function(){
        // loops over the divs

            if(jQuery(this).attr("myflagc")=="notok"){
                var photosetclength = jQuery(this).find('img').length;
                var totalcomplete = 0;
                jQuery(this).find('img').each(function(){
                    if(this.complete){
                        totalcomplete++;
                    }
                })
                if(totalcomplete==photosetclength){
                    sortpho(jQuery(this));
                    completedsts++;
                }
            }
            else{
                completedsts++;
            }
    })
    if(infscrolllength != completedsts){
        imagesloaded();
    }

}

function sortpho(setselector){
    setselector.css({"position":"relative"});
    setselector.css({"visibility":"visible"});
    setselector.attr({"myflagc":"ok"});
}

jQuery(document).ready(function(){
imagesloaded();

});

This code however doesn't seem to work for unknown reasons. What I noticed however is that if I add an alert anywhere in the imagesloaded() function it works properly which generally means that DOM isn't ready but since I'm using the jQuery(document).ready it can't be that. I also tried to add an alert at the end of this block :

if(infscrolllength != completedsts){
    imagesloaded();
    alert("not completed yet");
}

I noticed that it triggers many times until all images are loaded which means the code is correct and therefore I don't understand why it isn't working without an alert.

I know I could bind the load event to every div but load has problems with cached images so I want to avoid using it.

Is there a workaround for this ? And more importantly, I want to understand why this code isn't working.

UPDATE : Workaround

As Christian Landgren mentioned (see answer); the JavaScript function keeps looping preventing the page from rendering (i.e loading content).

I found a workaround to achieve what I want and without relying completely on the .load method. Here is the code :

function imagesloaded(){
    var mysets=[];
    var setnbr=0;
    var iditer=0;
    jQuery('#infscroll .photossetc').each(function(){
        jQuery(this).attr({"id":"photosetn"+iditer});
    // giving a unique id to every div
        iditer++;
    })
    jQuery('#infscroll .photossetc').each(function(){
        var myset=[];
    // creating an array to hold the following info 0:id of div - 1: nbr of images in div - 2: nbr of images that finished loading
        myset[0]=jQuery(this).attr("id");
        myset[1]=jQuery(this).find('img').length;
        myset[2]=0;
        jQuery(this).find('img').each(function(){
            if(this.complete){  // for when the image is already cached or already loaded
                myset[2]=myset[2]+1;
            }
            else{ // for when the image isn't cached nor loaded yet
                jQuery(this).load(function(){
                    for(i=0;i<mysets.length;i++){
                        var myiset=mysets[i];
                        if(jQuery(this).parents('#infscroll .photossetc').attr("id")==myiset[0]){
                            myiset[2]=myiset[2]+1;
                            if(myiset[1]==myiset[2]){
                                jQuery('#'+myiset[0]).css({"position":"relative","visibility":"visible"});
                            }                                   
                            mysets[i]=myiset;
                        }
                    }
                })
            }
        })
        if(myset[1]==myset[2]){
            jQuery('#'+myset[0]).css({"position":"relative","visibility":"visible"});
        }
        mysets[setnbr]=myset;
        setnbr++;
    })
}
wuerfelfreak
  • 2,118
  • 1
  • 10
  • 24
Ilyes Ferchiou
  • 563
  • 2
  • 9
  • 22

1 Answers1

0

Javascript is blocking which means that your loop here will block all javascript execution until the statement is met. When you add an alert you at least let the background layout threat load the images in the background until you press OK and your loop continues.

If you want to keep track on how many images have loaded you need to attach an onload event on each image which independently updates the loadcounter.

Something like this:

var loadCounter = 0;

function allDone(){
  // all images are loaded.
}

function imageLoaded(){
  loadCounter++;
  if (loadCounter === $('img').length){
    allDone();
  }
}

$('img').on('onload', imageLoaded)

When you say you can't afford to use the onload event, can you elaborate? You need to track the load event to know when all are loaded. I have used it successfully and it works good with cached images too - haven't had any problems with those at all.

Another (less sofisticated) option would be to globally check loaded count with intervals.

Another tip on the way, if you are developing a infinite scroll, you need to use a queue to handle which images you start loading. There are currently no way of aborting individual image requests. That means as soon as you have added your image to the DOM tree it will be queued in the layout engine and you can not remove that image from the queue.

A good way to solve this is to use the Async.queue mechanism and attach the onload event to the async next method.

Christian Landgren
  • 11,124
  • 6
  • 31
  • 31
  • Thank you for you answer, if I understood correctly, if a JavaScript code is running, the layout stops rendering until all JavaScript is code is done ? In other words, the JavaScript code and the layout rendering of the browser run in the same thread ? – Ilyes Ferchiou Apr 09 '14 at 08:24
  • Also, the problem with the load function is that if the images are cached, it doesn't fire. It is mentioned in the API reference : https://api.jquery.com/load-event/ Look at section : Caveats of the load event when used with images – Ilyes Ferchiou Apr 09 '14 at 11:11
  • Yes, that's the problem. You could use a separate worker process if you want - look up [Web Worker](https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers). (I have used the load event and it works fine in Safari, Chrome and Firefox, even on cached images.) – Christian Landgren Apr 09 '14 at 16:00
  • 1
    Thank you a lot. This explains everything. I'll check more the load function but I found a workaround, I'll update my post with the workaround. – Ilyes Ferchiou Apr 09 '14 at 17:59