1

I'm practicing parallax, so during the scroll i need element's offsetTop and height. And i know, that it's triggers layout each time, when you "get" this style properties, so it's affects overall perfomance. I decided to set custom attributes for each element with function and update it on window resize:

function setAttrs() {
  $sections.each(function() {
    var offsetTop = $(this).offset().top,
        height = $(this).height();
    $(this).attr({"data-offset": offsetTop, "data-height": height});
  });
}

setAttrs();

$(window).on("resize", function() {
  setAttrs();
});

So, my question is - does attribute getter inside scroll handler affects perfomance somehow? Something like this:

var height = $(this).attr("data-height");

I'm sort of 90% sure that this is good way, but i need to be sure.

Nikolay Talanov
  • 706
  • 4
  • 15
  • Instead of `var height = $(this).attr("data-height");`, use `var height = $(this).data("height");`. jQuery has a getter / setter for `data` attributes. – Cerbrus Mar 26 '15 at 15:01
  • @Cerbrus I think both `.attr()` and `.data()` methods of fetching HTML5 `data-` attributes are legit. The only issue is that `.data()` does not allow for writing (which OP doesn't need in this case, but good to know), and that it fetches the value at runtime and dynamic changes to the attribute value will not be reflected in `.data()`, but will do so in `.attr()`. – Terry Apr 11 '15 at 20:02
  • 1
    @Terry: Since when doesn't [`.data()`](https://api.jquery.com/jquery.data/) allow write actions? And since when doesn't it reflect the latest state of the DOM? That's just silly... – Cerbrus Apr 11 '15 at 20:11
  • @Cerbrus It does allow write, but does not modify the DOM: http://stackoverflow.com/questions/17762906/cant-update-data-attribute-value-jquery It writes to the jQuery data object instead. – Terry Apr 11 '15 at 21:00
  • And why is that a problem? If you're using data attributes, you generally want to get / set it using the same library any way. – Cerbrus Apr 11 '15 at 21:01
  • @Cerbrus Some people might want to modify the value in the DOM itself, and not the jQuery data. So yes, before you call "silly" on me, try this: http://jsfiddle.net/teddyrised/n12w7v13/ – Terry Apr 11 '15 at 21:04

3 Answers3

3

First, that's not really the best way to set the value of data-* attributes:

$(this).data({ offset: offsetTop, height: height });

That doesn't touch the DOM - jQuery maintains the values in its own data structure. It will read data-* attributes when they're first referenced from a particular element, but it won't update them in the DOM. References should also be made with .data():

var savedHeight = $(this).data("height");

Note that you drop the "data-" prefix when using the .data() API.

Second, anything you do with the DOM in a "resize" handler will affect performance, because browsers fire "resize" extremely rapidly while a window is being interactively resized. It's usually a good idea to make sure that your "resize" handler only does any work once every 50 or 100 milliseconds at most. There are a few different approaches to doing that, depending on the effect you're trying to achieve.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • 1
    1) I knew about .data api, but i wasn't aware that it works differently. Thx for answer, i will use this. 2) I know about resize, i will use debounce function later, provided code is more like proof of concept. – Nikolay Talanov Mar 26 '15 at 15:06
  • @NikolayTalanov OK :) Good luck!! – Pointy Mar 26 '15 at 15:09
3

When you're talking about performance:

As your using $(this) in three places in that each callback, its better to store it in a variable. It would avoid some overhead as well.

function setAttrs() {
  $sections.each(function() {
    var $self = $(this);
    var offsetTop = $self.offset().top,
        height = $self.height();
        $self.data({"offset": offsetTop, "height": height});
  });
}

Other things as @Pointy mentioned.

mohamedrias
  • 18,326
  • 2
  • 38
  • 47
3

Late to the party – but I have some benchmarks up my sleeve.

As for the raw Element.getAttribute, it never causes a reflow. In some browsers it’s still significantly slower than accessing cached data, in others not (jsPerf).

However, jQuery’s $().attr is always much slower than the native Element.getAttribute (jsPerf). Probably wrapping DOM methods with another function prevents browsers from optimizations – I’ve already run across this thing.

As others pointed out, $().data should be much faster than $().attr. Here’s a jsPerf for that, though I couldn’t access the results due to network problems.

tomekwi
  • 2,048
  • 2
  • 21
  • 27