2

I'm trying to write some image transitions in Javascript.

Page is here: http://shineemc.com/trans/

(All code is in a single page, just do a "view source")

I have one part of my code that is seriously slow. I have tried it a few different ways, but it's slow no matter what. I have done some logging, and it seems to be when getting the position of an element the very first time:

2016-02-01 15:54:28.386 (index):72 Setting BG position
2016-02-01 15:54:28.387 (index):83 In Each loop
2016-02-01 15:54:30.029 (index):85 Got div position
2016-02-01 15:54:31.148 (index):87 Set one BG
2016-02-01 15:54:31.148 (index):83 In Each loop
2016-02-01 15:54:31.171 (index):85 Got div position
2016-02-01 15:54:31.172 (index):87 Set one BG


console.log("Setting BG position");
$tiles.each(function() {
        console.log("In Each loop");
        var pos = $(this).position();
        console.log("Got div position");
        $(this).css( 'backgroundPosition', -pos.left +'px '+ -pos.top +'px' );
        console.log("Set one BG");
    });

If you look at the log timestamps, there's a big delay between when it first enters the "each" loop to when it gets the first position for a tile. (~1.7 secs)

I have tried doing this as a for loop, thinking that the "each" was being it's usual slow self, but the behavior carries over.

Using "for" loop:

2016-02-01 16:08:25.473 (index):72 Setting BG position
2016-02-01 16:08:25.474 (index):74 In For loop 1
2016-02-01 16:08:27.147 (index):77 Got div position
2016-02-01 16:08:28.299 (index):79 Set one BG
2016-02-01 16:08:28.300 (index):74 In For loop 2
2016-02-01 16:08:28.320 (index):77 Got div position
2016-02-01 16:08:28.321 (index):79 Set one BG


for (var i = 1; i < num_tiles; i++) {
        console.log("In For loop", i);
        var curTile = $('#tile'+i);
        var pos = curTile.position();
        console.log("Got div position");
        curTile.css( 'backgroundPosition', -pos.left +'px '+ -pos.top +'px' );
        console.log("Set one BG");
    }

I have used ID's instead of class selectors, Appended from a long string instead of making jQuery do it 36 times... I'm out of ideas.... What could be slowing this code down, and how can I get it up to speed?

Thanks in advance for any help.

3
  • You might try using Chrome's performance profiler to pinpoint the problem. "The Timeline panel lets you record and analyze all the activity in your application as it runs. It's the best place to start investigating perceived performance issues in your application." Commented Feb 1, 2016 at 21:34
  • Thanks Roberto, I used the timeline profiler to find out where the slowness was, I just don't know how to fix it :) Commented Feb 1, 2016 at 21:43
  • It looks like you are forcing synchronous layout which causes browser to perform recalc style and layout on each iteration of your loop. Try doing the positons reads in one batch and style updates in another batch. developers.google.com/web/fundamentals/performance/rendering/… Also, console.time('someKey'); and console.timeEnd('someKey') is much better API to profile script execution time. Commented Feb 1, 2016 at 21:50

2 Answers 2

4

It looks like you are forcing synchronous layout which causes browser to perform recalculate style and layout on each iteration of your loop.

Try doing the positions reads in one batch and style updates in another batch.

// Get array of all tile DOM elements
var tiles = Array.prototype.slice.call(document.querySelectorAll('.tile'));

// Read batch
var positionData = tiles.map(function (tile) {
    return {
        tile: tile,
        position: {
            left: tile.offsetLeft,
            top: tile.offsetTop
        }
    }
});

// Write batch
positionData.forEach(function (positionData) {
    var tile = positionData.tile;
    var position = positionData.position;

    tile.style.backgroundPosition = -position.left +'px '+ -position.top +'px';
}); 

Also, console.time('timerName'); and console.timeEnd('timerName') is a better API to profile script execution time.

Sign up to request clarification or add additional context in comments.

2 Comments

I appreciate the effort. Using this code, I still get layout thrashing. Using your code It still takes 1.7 seconds. Actually, I'm at home now, and the old code completes in 1.5 seconds due to my faster computer. Same for Firefox. Your code 853ms, my code 875ms. I have saved a copy of the file with your code active at: shineemc.com/trans/indexp.html Thanks again for the help.
I have figured it out. by loading the image data in a previous step via CSS, I forced a paint event for each tile when I made the read query for position. By setting the background image data at the same time as the position, I avoid that paint event and only have to paint once with the proper position data set. Thank you very much for pointing me in the right direction! I really appreciate it.
1

I don't know whether this is the actual reason of the problem but I saw a question about performance and I wrote something I read here. Just like there, DOM query performances compared with jquery and raw js are :

vanilla - document.getElementById('test-table') => 12,137,211 (ops/sec)
jQuery - $('#test-table') => 350,557 (ops/sec)

Even if this may not be the real problem solver for this but It's obvious that It can speed your performance up. I hope that helps.

1 Comment

Thanks for the comment. Even if I do this non jQuery, it doesn't really change performance. I think Prashant is on the right track, but I haven't been able to crack this one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.