I would not want to argue with the creator of jQuery, but having a brilliant mind does not necessarily mean that you are always right, of course. Using scroll delays can ruin any event-based animation. I spent a ridiculous time studying the scroll event and creating plugins and demos based on it, and this seems like an urban myth that it causes most devices most often.
Here's a small demo to check the amount - the maximum, apparently, is the screen refresh rate:
Codepen
If the browser does not have smooth scrolling enabled, mousewheeling or panning will only trigger one event. And even if this is not the case, most machines are very well equipped to handle as many calls as the frame rate allows - provided that the rest of the web page is well built.
The last bit is the biggest problem, browsers can handle quite a bit of script at short intervals, but what can slow down execution is the heavily written markup. Therefore, the biggest bottlenecks are often repainted. This can be well verified using developer tools.
Some examples of this have large blocks of fixed position elements and animations that are not based on transform , but use pixel values instead. Both run unnecessary replication, which have a huge impact on performance. These problems are not directly related to how often the lights scroll.
The use of fixed position elements can be prevented by using this hack in webkit-related browsers:
.fixed { -webkit-backface-visibility: hidden; }
This creates a separate stacking order, making the content independent of its environment and preventing repainting of the full page. Firefox seems to do this by default, but unfortunately I have not yet found a property that will work with IE, so it’s best to avoid such elements anyway, especially if their size is a large part of the viewport.
At the time of this writing, the following has not been implemented.
And that will be requestAnimationFrame , which now has very good browser support. At the same time, functions can be performed in such a way that they are not forced into the browser. Therefore, if there are complex functions in the scroll handler, it would be very useful to use this.
Another optimization is to use the check box and do not run anything if necessary. A useful tool in this can be adding classes and checking their presence. Here's the approach I usually use:
$(function() { var flag, modern = window.requestAnimationFrame; $(window).scroll(function() { if (!$(this).scrollTop()) { if (flag) { if (modern) requestAnimationFrame(doSomething); else doSomething(); flag = false; } } else if (!flag) { if (modern) requestAnimationFrame(doMore); else doMore(); flag = true; } }); function doSomething() {
And an example of how to switch a class can be used to determine a boolean value:
$(function() { var modern = window.requestAnimationFrame; $(window).scroll(function() { var flag = $('#element').hasClass('myclass'); if (!$(this).scrollTop()) { if (flag) { if (modern) requestAnimationFrame(doSomething); else doSomething(); $('#element').removeClass('myclass'); } } else if (!flag) { if (modern) requestAnimationFrame(doMore); else doMore(); $('#element').addClass('myclass'); } }); function doSomething() {
If this does not interfere with any desired functionality, debugging the event can be a good approach, of course. It could be simple:
$(function() { var doit, modern = window.requestAnimationFrame; $(window).scroll(function() { clearTimeout(doit); doit = setTimeout(function() { if (modern) requestAnimationFrame(doSomething); else doSomething(); }, 50); }); function doSomething() {
In the comments below, Kayido had some valid points. Besides the need to raise the scope of the variable that determines the timeout, this approach may not be very useful in practice, because it will only perform the function after the scroll is completed. I would like to refer to this interesting article , which led to the conclusion that what would be more effective than the debut is throttling - make sure that the events control the function only with the maximum amount per unit of time, closer to what was suggested in question. Ben Alman made a nice little plugin for this (note that it was written in 2010 already).
Example
I managed to extract only the part necessary for throttling, it can still be used in the same way:
$(window).scroll($.restrain(50, someFunction));
Where the first argument is the time during which only one event will execute the second parameter - the callback function. Here is the basic code:
(function(window, undefined) { var $ = window.jQuery; $.restrain = function(delay, callback) { var executed = 0; function moduleWrap() { var elapsed = Date.now()-executed; function runIt() { executed = Date.now(); callback.apply(this, arguments); } if (elapsed > delay) runIt(); } return moduleWrap; }; })(this);
What happens inside an executable function can still slow down the process. One example of what should always be avoided is the use of .css() to set the style and place any calculations in it. This is pretty bad for performance.
It should also be mentioned that the marking code makes more sense when switching at a certain point to the bottom of the page, and not from the top, because this position does not work repeatedly. Thus, a check of the flag itself can be excluded in the scope of the question.
Fulfilling this right, it makes sense to also check the scroll position on the page load and switch based on this. Opera is particularly stubborn with this - it resumes the cached position after the page loads. Therefore, a small timeout is best suited:
$(window).on('load', function() { setTimeout(function() {
In general, I would say - do not avoid using the scroll event, it can provide very nice effects on the web page. Just be careful how it all sticks together.