最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - CSS Sprites performance - Stack Overflow

programmeradmin1浏览0评论

I have static image 500x640 sitting in folder catted by 20x20 pieces with css sprites, I am setting background-position to display each piece, I need such kind of display to be able to manipulate with each piece later.

css:

   .piece
        {
            width: 20px;
            height: 20px;
            display: inline-block;
            //display: inline;
            //zoom:1;
        }        

    .ob { background-image: url("/Images/ob.jpg");}

js:

<script id="flipTemplate" type="text/html">
    <div class="piece ob" data-bind="style: { backgroundPosition: viewModel.getLeftValue($index) + ' ' + viewModel.getTopValue($index) }, attr: {cond: Cond, id: Id }, click: viewModel.setClick ">
                </div>
</script>
<script type="text/javascript">
    viewModel = {
        flips: ko.observableArray([]),      

        setClick: function (data, e) {
            e.preventDefault();            
            //doing click
        },

        getLeftValue: function (index) {

            var position = 0;

            var currentLine = div(index(), 25);

            if (currentLine > 0)
                return '-' + (index() - (currentLine * 25)) * 20 + 'px';
            else
                return '-' + index() * 20 + 'px';
        },

        getTopValue: function (index) {

            return '-' + (div(index(), 25)) * 20 + 'px';
        }
    };    

    ko.applyBindings(viewModel);
</script>
function div(val, by){
    return (val - val % by) / by;
}

So am having some performance issues. For example in Opera and FF images loading very quickly about 1 sec, in IE about 3 sec, but in Chrome it is loading very slow

it is taking about 17 sec to display all pieces in Chrome...

Browser doing just one request to get the image and than cutting small pieces from it, why it may take so long in Chrome?

Is there any way i can improve performance?

just did CTRL+Refresh and here strange loading result:

UPDATE: I just placed a sample here:

UPDATE: In my sample there is JSON array, it is contains 800 elements, so I just find out if I make it less, eg 600-700 elements the performance is getting better, but I need 800 elements anyway.

e.g When there is only 600 elements it is reducing the load in Chrome to about 6 sec....

So probably may be the problem somewhere at the point where knockout iterating template?

I have static image 500x640 sitting in folder catted by 20x20 pieces with css sprites, I am setting background-position to display each piece, I need such kind of display to be able to manipulate with each piece later.

css:

   .piece
        {
            width: 20px;
            height: 20px;
            display: inline-block;
            //display: inline;
            //zoom:1;
        }        

    .ob { background-image: url("/Images/ob.jpg");}

js:

<script id="flipTemplate" type="text/html">
    <div class="piece ob" data-bind="style: { backgroundPosition: viewModel.getLeftValue($index) + ' ' + viewModel.getTopValue($index) }, attr: {cond: Cond, id: Id }, click: viewModel.setClick ">
                </div>
</script>
<script type="text/javascript">
    viewModel = {
        flips: ko.observableArray([]),      

        setClick: function (data, e) {
            e.preventDefault();            
            //doing click
        },

        getLeftValue: function (index) {

            var position = 0;

            var currentLine = div(index(), 25);

            if (currentLine > 0)
                return '-' + (index() - (currentLine * 25)) * 20 + 'px';
            else
                return '-' + index() * 20 + 'px';
        },

        getTopValue: function (index) {

            return '-' + (div(index(), 25)) * 20 + 'px';
        }
    };    

    ko.applyBindings(viewModel);
</script>
function div(val, by){
    return (val - val % by) / by;
}

So am having some performance issues. For example in Opera and FF images loading very quickly about 1 sec, in IE about 3 sec, but in Chrome it is loading very slow

it is taking about 17 sec to display all pieces in Chrome...

Browser doing just one request to get the image and than cutting small pieces from it, why it may take so long in Chrome?

Is there any way i can improve performance?

just did CTRL+Refresh and here strange loading result:

UPDATE: I just placed a sample here: http://bit.ly/TrcCdp

UPDATE: In my sample there is JSON array, it is contains 800 elements, so I just find out if I make it less, eg 600-700 elements the performance is getting better, but I need 800 elements anyway.

e.g When there is only 600 elements it is reducing the load in Chrome to about 6 sec....

So probably may be the problem somewhere at the point where knockout iterating template?

Share Improve this question edited Aug 29, 2012 at 15:39 angularconsulting.au asked Aug 28, 2012 at 17:32 angularconsulting.auangularconsulting.au 28.3k14 gold badges90 silver badges105 bronze badges 22
  • Sorry, the picture's a little small. How big is your sprite? – canon Commented Aug 28, 2012 at 17:36
  • @canon if you right click on image and press open it will open in real size(i.sstatic/WGdAr.jpg). My sprite is 83.78kb. – angularconsulting.au Commented Aug 28, 2012 at 17:43
  • @SLaks i will see what i can do, it may take some time. – angularconsulting.au Commented Aug 28, 2012 at 17:44
  • That's odd, you get a 304 Not Modified response, yet it takes 17 seconds for it to load. Does loading the image manually (e.g. navigating to it) also take long? – pimvdb Commented Aug 28, 2012 at 18:11
  • 3 I don't think the problem is related to your images. Why are you requesting images after the js? Put css and images first and later JS and see if the problem will continue.. – Thiago Custodio Commented Aug 28, 2012 at 18:37
 |  Show 17 more ments

3 Answers 3

Reset to default 4

The problem is not the image. The image can be fixed by placing a preload at the top, before any of the stylesheet or script tags:

<meta name="viewport" content="width=device-width">

<script type="text/javascript">
    var img = new Image();
    img.src = 'TestApp_files/obm000.jpg';
</script>

<link href="TestApp_files/jquery00.css" rel="stylesheet">
<link href="TestApp_files/jquery01.css" rel="stylesheet">
<!-- ad nauseum -->

After this, the image loads in 170ms (locally). However, the page still mucks about for another 10-15 seconds afterwards trying to decide what to do.

The root issue is that the javascript is an absolute mess. Image/file/function names are cryptic. Things in the middle of the page depend on code at the end depends on code at the beginning depends on code at the end. Controller/view/model logic is all over the map. Global variables and multi-file coupling... hokay, </soapbox>, now onto treating the symptom.

Problem 1: binding knockout before the DOM loads

Put applyBindings into a domready callback:

jQuery(function($) {
   ko.applyBindings(viewModel);
});

Problem 2: foreach is slow

The knockout foreach binding is incredibly slow with large data sets. You can try jQuery templates and move the foreach inside the template, as described in this SO question. It seems to drop the time down to about 3 seconds.

I don't really understand why this is necessary as it seems to render fine with your current foreach, it simply hangs forever while knockout does some magic in the background that, as far as I can tell, takes place after foreach pletes.

Side note: is it necessary to put flips into an observable array? I assume you intend to use that later as nothing in the current code needs it. If not, take it out and it will help performance (though it won't solve this issue).

Cheers, I hope this helps.

It’s some sort of strange rendering bug between the foreach binding and Chrome. I tried just adding a character in your template before the div and that fixed the delay (but also messed up the layout).

A good way to fix this is to use something other than foreach. My repeat binding works well here and solves the delay problem.

Here is that section of your code using repeat:

<div class="condListHolder" style="width:558px">
    <div class="cond2" title="Click to flip" data-bind="repeat: flips">
        <div class="piece obm" data-bind="
          style: { backgroundPosition: getLeftValue($index) + ' ' + getTopValue($index) },
          attr: {cond: $item().cond, id: $item().Id },
          click: setClick "></div>
    </div>
</div>

Because repeat doesn’t use an observable for $index, you’ll also need to change your getTopValue and getLeftValue functions to take out the parentheses () after index.

You should also look into streamlining your code that is called by the foreach loop. I don't know how often you call the getLeftValue and getTopValue methods but they are pretty unoptimized.

  • Try limiting function calls that give you the same result, use local vars to cache since they are cheap
  • don't concatenate strings in large loops, this is way slower than using an array to join them.

I tried optimizing your two functions. You should see at least some improvement:

getLeftValue: function (index) {

    var position = 0,
        realIndex = index(),
        currentLine = div(realIndex, 25);


    if (currentLine > 0)
        return ["-", (realIndex - (currentLine * 25)) * 20, "px"].join("");
    else
        return ["-", realIndex, "px"].join("");
},

getTopValue: function (index) {

    return ["-",(div(index(), 25)) * 20,"px"].join("");
}
发布评论

评论列表(0)

  1. 暂无评论