16

Update: Similiar question with a very good answer that shows how to use requestAnimationFrame with scroll in a useful way: scroll events: requestAnimationFrame VS requestIdleCallback VS passive event listeners


So let's say I want to add some expensive action on my site triggered by scrolling. For example, I'm using parallax effects in my jsfiddle.

Now I keep reading it must not be bound to the event directly, sometimes followed by snippets that are meant to be better. Just some examples:

  1. Attaching JavaScript Handlers to Scroll Events = BAD!
  2. How to develop high performance onScroll event?
  3. How to make faster scroll effects?
  4. 60FPS onscroll event listener

What they say is basically don't do this:

  // Bad guy 1
  $(window).scroll( function() {
    animate(ex1);
  });

or this

  // Bad guy 2
  window.addEventListener('scroll', onScroll, false);
  function onScroll() {
    animate(ex2);
  }

But use timeouts, intervals, requestAnimationFrame and whatnot, for example:

  // Good guy
  $(window).scroll( function() {
   scrolling1 = true;
  });

  setInterval( function() {
    if (scrolling1) {
      scrolling1 = false;
      animate(ex3);
    }
  }, 50 );

So, I went and added the options I found in the links above to a jsfiddle that tries to compare them by adding a counter to every approach, like so:

  // Test
  $(window).scroll( function() {
    counter = counter + 1;
    // output result of counter
    animate(ex1);
  });

Best to check the complete jsfiddle

Outcome: Everything that works smooth is about the same number of calculations. If I can live with choppy effects, maybe I can safe some resources. And against everything I read, this seems logical to me!

First question: Am I missing something or is this a valid test? If it's invalid, how could I test correctly? Edit: To clarify, I want to test whether any of the above methods save performance at all.

Second question: If it is valid, why is everyone nervous about onscroll? If fluid animations require 5000 calculations over the complete site, there's no way to change it anyway?

(Well, sometimes I use checks to determine whether an object is in the viewport or not, but honestly I don't even know if those checks aren't as expensive as the prevented code itself, especially if they involve five different variables such as offset, windowHeight, scrolltTop, getBoundingClientRect and outerHeight...)

user127091
  • 2,071
  • 2
  • 9
  • 16
  • 1
    What are you testing? Performance? Independent of browser (javascript engine), device, operating system? You'd need to test all of those things... but anyways I thought you should use passive event listeners or something for scroll events – Cody G Jul 13 '18 at 17:19
  • 1
    https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Improving_scrolling_performance_with_passive_listeners Looks like it's automatic for chrome and firefox these days... on `touchstart` and `touchend` – Cody G Jul 13 '18 at 17:20
  • 2
    And finally, https://developer.mozilla.org/en-US/docs/Web/Events/scroll – Cody G Jul 13 '18 at 17:26
  • Thanks Cody. I'm trying to verify if any of the above methods are actually optimizing the performance or if it's unnecessary. I added that to my question. I'll read through the links more carefully soon. (Looks like I should test it in an old browser to see more difference between the approaches?) – user127091 Jul 13 '18 at 17:47
  • Lol, I was going to test in IE11 for you but I can't even load jsfiddle in it. But yeah I wonder how iOS/Safari handles scroll events. I think it's a very specific topic and I hope someone that has researched it within the last year or so can chime in – Cody G Jul 13 '18 at 17:48
  • I added a link above that works on mobile, IE11 etc. I found there's not much difference though. – user127091 Jul 14 '18 at 11:14
  • I've read the links above now as well. Findings: A) According to Mozilla event listeners are now passive by default in Firefx and Chrome. B) Mozilla themselves say request animation frame is useless in this case as it's fired at the same rate (true according to my test). That leaves the interval and timeout options, which are choppy if not set to neraly the same rate as it would fire anyway. – user127091 Jul 14 '18 at 11:22

2 Answers2

11

So, @SirPeople already answered your first question correctly, it is indeed a good test to see how often the animate function gets called, but it's a bad test to compare the performance of the different snippets.

This is a performance recording of the excecution:

performance test

The function animate isn't expensive at all. I took a performance recording (next picture), which shows that it takes between 0.64ms and 1.29ms in the one iteration I looked at (points 1-5). And once the function is done, the repaint takes no time at all (point 6), which might be because the page has almost no content. When we take a look at the time, we can see that all five animation functions and the repaint happen in less than 10ms, which, under normal circumstances, mean that we can get a fluid 60fps animation (point 7).

Also, if we want to compare onscroll event listeners we need to test each on it's own and compare the results. If one of the listeners would really be blocking it would have an influence on the whole page and without performance debugging you wouldn't know which one it was.

I made two jsfiddles window.scroll and RAF. And, to my surprise, there does not seem to be any difference.

Why are people concerned about this?

As you can see in the jsfiddles linked above, if the event handlers get too large, the entire page is going to lag.

Now what?

I'm no performance guru myself, but:

Sandro
  • 1,051
  • 7
  • 15
  • 1
    Nice, thanks. I didn't try to make the animate function more expensive and it's also more logical to compare the methods on seperate sites. I guess with your answer, Cody's comments and the answer from @SirPeople there's not much left to say. Let's see if the intersection observer changes things in the future. – user127091 Aug 03 '18 at 11:13
  • Hey, great answer but unfortunately the fiddles 404 now.- anyone got similar examples? im trying to really understand this topic – user3674592 Jul 29 '22 at 10:13
  • also [MDN](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners) says : "You don't need to worry about the value of passive for the basic scroll event. Since it can't be canceled, event listeners can't block page rendering anyway." So passive is enabled by default for scroll events and hence wont make a difference? – user3674592 Jul 29 '22 at 10:22
9

I am not totally sure if I got correctly your questions and all your statements but I will try to give you an answer:

  • Am I missing something or is this a valid test? If it's invalid, how could I test correctly?

It is a valid test if you are measuring the number of times a function has been called, this will of course depend on the browser, SO, if is GPU enhanced and some other benchmark parameters that has been commented in your question already.

If we consider that measurement correct then it can be said that by using timeouts or requestAnimationFramework could save time because we are basically following the principles of debouncing or throttling. Basically we do not want to request or called a function more times than is needed. In the case of the timer we will queue less functions calls and in the case of requestAnimationFrame because it enqueue calls before repainting and will execute them sequentially. In timeouts it could happen that calculations overlap if they are very heavy.

I found a better answer in why using requestAnimationFrame explaining the main problems with animations in the browser like Shear, flickering or frame skip. It also includes a good demo.

I think your testing method is correct, you also should interpret it correctly, maybe calls are close to be the same number because of your hardware and your engine, but as said, debounce and throttling are a performance relieve.

Here also one more article supporting not attach handlers to window scroll from Twitter. (Disclaimer: this article is from 2011 and browsers have deal with optimizations for scroll in different ways).

  • why is everyone nervous about onscroll? If fluid animations require 5000 calculations over the complete site, there's no way to change it anyway?

I do not think there is nervousness in the performance hit, but the user experience will be worst for the above mentioned animation problems that your overcalling of scroll can cause, or even if there is a desynchronization with your timer you could still get the same 'performance' problems. People just recommend saving calls to scroll because: Human visual permanence doesnt require a super high frame rate and so it is useless to try to show images more often. For more complex calculations or heavy animations browsers are already working on optimizations, like you have check, some browsers had optimize this things in comparison with the 2, 3 or 6 years ago the articles you expose were written.

SirPeople
  • 4,248
  • 26
  • 46
  • Thanks a lot for this, it is very helpful. I'll nevertheless mark Sandros answer correct now as it points out where the problem starts (expensive animate function) with the performance rec and it shows how to compare better (not running all examples on one page). Still, your answer helps, thanks again! – user127091 Aug 03 '18 at 11:10
  • Hey, glad you find the answer useful. No problem about the answer, I also like his analysis with the browser. – SirPeople Aug 04 '18 at 15:13