JQuery scroll event freezes page

261
December 10, 2016, at 1:10 PM

I setup a trigger which checks if an element is in the viewport (visible on the screen) and added it to the scroll event. This works fine on some pages, but large pages it freezes the page. On firefox I can't scroll at all, it crashes the page completely and an alert comes up telling me that jquery is not responding. Heres the trigger:

 $(window).on("scroll", function () {
     $('div').each(function () {
         if ($(this).isOnScreen(true)) {
             $(this).trigger('report.appear');
         }
     });
 });

and heres the isOnScreen function (which finds out what elements are in the viewport):

$.fn.isOnScreen = function () {
     var win = $(window);
     var viewport = {
         top: win.scrollTop(),
         left: win.scrollLeft()
     };
     viewport.right = viewport.left + win.width();
     viewport.bottom = viewport.top + win.height();
     var bounds = this.offset();
     bounds.right = bounds.left + this.outerWidth();
     bounds.bottom = bounds.top + this.outerHeight();
     return (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom));
 };

It doesn't matter how many div elements are on the page, it seems to be just large amounts of any content that crashes it, or at least large HTML tables that I have. Is there another way to detect when an element appears on the screen without using the scroll event? Or is there a way to use scroll without crashing jquery?

UPDATE:

When I comment out this:

 $(window).on("scroll", function () {
     $('div').each(function () {
         /*
        if ($(this).isOnScreen(true)) {
            $(this).trigger('report.appear');
        }
        */
     });
 });

it works fine, so its the isOnScreen function thats causing the problem. Is there a better way to do this which won't overload the browser like this?

Answer 1

MDN: scroll:

Since scroll events can fire at a high rate, the event handler shouldn't execute computationally expensive operations such as DOM modifications. Instead, it is recommended to throttle the event using requestAnimationFrame, setTimeout or customEvent, as follows:

;(function() {
    var throttle = function(type, name, obj) {
        obj = obj || window;
        var running = false;
        var func = function() {
            if (running) { return; }
            running = true;
            requestAnimationFrame(function() {
                obj.dispatchEvent(new CustomEvent(name));
                running = false;
            });
        };
        obj.addEventListener(type, func);
    };
    /* init - you can init any event */
    throttle ("scroll", "optimizedScroll");
})();
// handle event
window.addEventListener("optimizedScroll", function() {
    console.log("Resource conscious scroll callback!");
});
Answer 2

I have written a plugin specifically for this: jQuery.isInView. It is designed to handle large numbers of elements, and large numbers of calls. (And it is tested for that.) That should do the job for you.

That aside, you definitely should throttle the scroll event. Even if browsers don't brick, you'll suck their battery dry on mobile. If you want to use an existing, proven solution, I'd suggest _.throttle in the Underscore library. Ben Alman also has an established $.throttle on offer. The MDN code, as posted in the answer of @t.niese, will certainly do the job as well.

READ ALSO
How to get id of selected row in autocomplete JQuery UI

How to get id of selected row in autocomplete JQuery UI

I would like to get the row id of selected item in my autocomplete function, I get the values of my source from a php variable

271
CodeIgniter : Show methods name as per controller name selected

CodeIgniter : Show methods name as per controller name selected

I have 2 dropdown in one of my web page build with CodeIgniterFirst dropdown is Controller Name and second one is Method Name

186
How can I dynamically disable popover from a DOM element?

How can I dynamically disable popover from a DOM element?

I have almost identical multiple divs on a pageThey all have graphs inside I want some of them to have popovers when they are hovered

289
ActionController::UnknownFormat in RegistrationsController#create (Devise)

ActionController::UnknownFormat in RegistrationsController#create (Devise)

I am trying to do Devise registration via modal window (remote: true) and do all in backend and by rendering javascript when some validation errors occurSo far I am in the middle of the road and my validation messages appear to be working just fine, but until the time I try to upload...

394