Ching Ching Ching Ching - 6 months ago 11
Javascript Question

Problematic browser performance when attaching event handler inside loop

I have a problem when creating plugin. The problem came up when setting new value for variable

width
.

width
variable need to calculate again, if user resizes his browser.
If i attach
resize
event inside loop, it will make trouble performance.
I came up with the idea to create
closure
function for wrapping all CODE. So, when the user resize his browser, i call this function again.

JS :

var self = this,
onScrollbarY = function() {
self.each(function() { // loop it
var el = $(this),
elLog = el.find(".scrollbarYLog"),
width = $(window).innerWidth(), // this value will change based on users browser width
onMouseOver = function() {
elLog.html(width);
};
elLog.on("mouseover", onMouseOver);
});
};
onScrollbarY(); // call it immediatly

$(window).on("resize", onScrollbarY); // if users resize its browser, call it again for getting new browser width


Is this the correct way to accompolished it? or there are other option which more efficient rather than attach all code again?

thanks in advance...

Answer

The reason why you had a performance problem in the first place is that every time you called .on('resize', ...), you registered a function that runs on that event. So after 5 resize events, you had 5 functions that were called every time, which is what caused the slow-down.

There are two ways to approach this problem:

  1. only attach one handler to that event (what you ended up doing); or
  2. use the .one('resize', ...) event handler to register a function that will only be triggered on the first next resize event.

Use case #1 is what the majority of developers use and recommend. You create a function (like your onScrollbarY) and you register that function using .on() to be called each time the resize event happens from the moment you register it.

The case #2 is very rare and you probably don't want to use .one() unless you only want to handle the first occurence of that event, and none after that. If you wanted to handle more than one, you would have to call .one() again after the event happens to tell it to listen for that event again.

EDIT: You can simplify your code to the following:

var $window  = $(window),
    width    = $window.innerWidth(), // we know the initial width
    $elLog   = $(".scrollbarYLog"),  // we find the scrollbar element
    onResize = function() {
      width = $window.innerWidth();
    },
    onMouseOver = function() {
      $elLog.html(width);
    };

// register the resize function with the "resize" event
$window.on("resize", onResize);
// register the mouseover function with the "mouseover" event on the scrollbar
$elLog.on("mouseover", onMouseOver);

// there is no need to call onResize(), as we've already set the width variable