Problematic browser performance when attaching event handler inside loop - javascript

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?

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:
only attach one handler to that event (what you ended up doing); or
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

Related

Code impact inside click event?

element.onclick = function() {
myFunction();
};
function myFunction() {
// 100, 500 or 1000 lines of code
}
Does and if yes, how does code inside the click event impacts the weight of click event?
PS! Im interested in code impact in event listener overall, not just a function like in my example. What if there was 500 lines of code instead of function?
Does it matter how big is myFunction() code?
Does it get processed before click event is triggered?
I do not mean the impact on the moment it's pressed but before this: if event is attached to element.
Im asking this because I need to attach the same click event to many elements and the code inside is pretty big. Event delegation is not an option in my situation. An example:
for(i = 0; i < 500; i++) {
//Just for the sake of this example
var element = document.createElement('div');
element.onclick = function() {
myFunction();
};
}
function myFunction() {
// 100, 500 or 1000 lines of code
}
Based on this example, should I be thinking about or worried about the size of myFunction()?
You function will be processed by the JavaScript runtime when it reads in the file. It will be invoked when you call it in the callback. The time for the callback to invoke the function will be no different if the function is 10 lines or 1000 lines.
Edit:
You may notice the execution time of the function change, as the amount of code increases, but invocation shouldn't change. Things that change invocation speed are looking up nested functions in objects: obj1.obj2.obj3.obj4.obj5.func() would be slower than a top-level func() definition (shouldn't be drastically different if it is not nested deep in large objects).
First, Javascript is a single threaded ecosystem.
There is a big eventloop which executes one event after another.
In case your onclick takes ages, you might see the prominent "A script is not responding"
The processing happens when you click it.
The "big event loop" reads the click event and calls all your event handlers for it. So the clicking triggers all the click event handlers being processed. (for the elements that are under your click area)
In case your problem is a not responding script, you could try WebWorkers. I never played with those, as it´s rather new.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
Regarding your 500 elements with the same click handler... You can only click one item at a time, no?
Maybe try
event.stopPropagation();

Meteor.js: How to set a div height dynamically via Javascript

I'm using templates/handlebars but none of the event handlers are triggered when the browser window resizes. Not sure how to capture the resize event in order to dynamically set the div's height to be within the viewport
Here's a sample of what I've tried so far using meteor's event map:
Template.basic.events({
'resize window' : function(evt, tmpl){
alert("test");
},
};
Ideally this handler would be called each time the window is resized so I can use $(window).height() to set the div's height in the html using tmpl.find('#main-div');.
Most problems which directly rely on jQuery can be solved using the onRendered callback like so:
Template.basic.onRendered(function() {
$(window).resize(function() {
console.log($(window).height());
});
});
Technically this works, but because window never gets removed as part of the rendering process, this technique has a big disadvantage: it adds a new resize handler every time the template is rendered.
Because window is always available, you can instead use the created and destroyed callbacks to register and unregister the handlers:
Template.basic.onCreated(function() {
$(window).resize(function() {
console.log($(window).height());
});
});
Template.basic.onDestroyed(function() {
$(window).off('resize');
});
Note, however, that stopping the resize handler in onDestroyed may not really be what you want. See this question for more details.
Also note that in the current version of meteor, you can check the number of event handlers like so:
$._data($(window).get(0), "events").resize.length

Javascript Custom Resize Event [duplicate]

This question already has answers here:
How to detect DIV's dimension changed?
(28 answers)
Closed 7 years ago.
I have a very simple question, or at least it seems that way.
I have a DIV element which will be resized at one moment. I want to be able to capture the resizing moment.
Something like this:
function myFunction(){
alert('The DIV was resized');
}
divElement.addEventListener("resize", myFunction, false);
Does anyone know the answer?
Thanks
As of December 2011, there's no built-in event to detect when a div resizes, just when a window resizes.
Check out this related question: Detecting when a div's height changes using jQuery, and this plugin from the solution to that question: http://benalman.com/projects/jquery-resize-plugin/
With jQuery resize event, you can now bind resize event handlers to
elements other than window, for super-awesome-resizing-greatness!
Why is a plugin needed for the resize event?
Long ago, the powers-that-be decided that the resize event would only
fire on the browser’s window object. Unfortunately, that means that if
you want to know when another element has resized, you need to
manually test its width and height, periodically, for changes. While
this plugin doesn’t do anything fancy internally to obviate that
approach, the interface it provides for binding the event is exactly
the same as what’s already there for window.
For all elements, an internal polling loop is started which
periodically checks for element size changes and triggers the event
when appropriate. The polling loop runs only once the event is
actually bound somewhere, and is stopped when all resize events are
unbound.
Sample Code
// You know this one already, right?
$(window).resize(function(e){
// do something when the window resizes
});
// Well, try this on for size!
$("#unicorns").resize(function(e){
// do something when #unicorns element resizes
});
// And of course, you can still use .bind with namespaces!
$("span.rainbows").bind( "resize.rainbows", function(e){
// do something when any span.rainbows element resizes
});
You can try this plugin - http://benalman.com/code/projects/jquery-resize/examples/resize/
There are various examples. Try resizing your window and see how elements inside container elements adjusted.
Example with js fiddle
In that resize() event is bound to an elements having class "test" and also to the window object and in resize callback of window object $('.test').resize() is called.
e.g.
$('#test_div').bind('resize', function(){
console.log('resized');
});
$(window).resize(function(){
$('#test_div').resize();
});
See this
My first thought is to use a custom event system. You can find a pure javascript one here ( http://www.nczonline.net/blog/2010/03/09/custom-events-in-javascript/ )
After including his code, you can do something like this:
function myFunction(){
alert('The DIV was resized');
}
div_elm = document.getElmentById('div-to-resize');
EventTarget.call(div_elm);
div_elm.addListener("resize", myFunction);
Then later, just add one line to wherever you are resizing the div.
div_elm.width += 100 //or however you are resizing your div
div_elm.fire("resize");
I think that should work for you.
EDIT:
If you are not the one coding the resizing, then my first thought is something like this:
var resizeScannerInterval_id = (function(div) {
var width = div.offsetWidth;
var height = div.offsetHeight;
var interval_id = setInterval(function() {
if( div.offsetWidth != width || div.offsetHeight != height )
width = div.offsetWidth;
height = div.offsetHeight;
div.fire();
}
},250);
})(document.getElementById('div-id'))
There is a very efficient method to determine if a element's size has been changed.
http://marcj.github.io/css-element-queries/
This library has a class ResizeSensor which can be used for resize detection. It uses a event-based approach, so it's damn fast and doesn't waste CPU time.
Please do not use the jQuery onresize plugin as it uses setTimeout() loop to check for changes. THIS IS INCREDIBLY SLOW AND NOT ACCURATE.

Is it safe to call jQuery's resize() function to execute my own resize handler?

I am defining a resize handler that positions some elements on the screen, like this:
$(window).resize(function() {
// Position elements
}
I also want to execute this functionality when the page first loads, so I just add the following right after the above code:
$(window).resize();
This works just fine. However, I'm wondering if I may trigger any side effects, harmful or not, by calling this function - I really just want to execute my own resize handler. Of course, I could do the following to make sure that I execute only my handler:
var positionElements = function() {
// Position elements
}
$(window).resize(positionElements);
positionElements();
However, I'm new to JavaScript and I want to keep my code as concise as possible - this adds some boiler plate code to the mix.
Edit: In fact, my code can be shortened even more by using chaining. Like this:
$(window).resize(function() {
// Position elements
}).resize();
I cant see how it should be harmful, anything that could be triggered by a resize that is actually destructive should be avoided in the first place. What you are doing by using calling $(window).resize() is the same as the user resizing the window.
TL;DR; Yes its safe.

MooTools/JS: bindWithEvent

There's this piece in the codebase I'm working on:
this.element.addEvent('click', this.clickEvent.bindWithEvent(this));
I want to change it so that the click event makes sure the window is loaded first. So I tried:
var t = this;
this.element.addEvent('click', function() {
window.addEvent('load', function() {
t.clickEvent.bindWithEvent(t));
});
});
That doesn't seem to get it to work though. What am I missing?
You're adding a handler to the load event when the user clicks something, _aftertheload` event has already fired. Therefore, nothing happens.
You should probably add the click handler inside of an event handler for the load event. (swap the two addEvent lines)
in mootools you tend to use domready and not load but essentially, doing it as suggested will not work as it lacks the context here:
this.element.addEvent('click', this.clickEvent.bindWithEvent(this));
so you are working within a class here - therefore, make sure you instantiate it on the domready event instead, something like...
window.addEvent("domready", function() {
// whatever you need to do...
var foo = new myClass($("someElement"), {option: value}); // example instantiation
// if the binding is not in the .initialize, then call the right method...
// foo.bindMyEvents();
});
as long as the class instance is within domready, you're fine. if that's not an option, see which method binds the events and call that on the domready instead.

Categories

Resources