addEventListener / attachEvent and passing 'this' to handler

E

Erwin Moller

Hi,

Considering the following code:
[https://developer.mozilla.org/en/DOM/element.addEventListener]

---------------------------------
if (el.addEventListener){
el.addEventListener('click', modifyText, false);
} else if (el.attachEvent){
el.attachEvent('onclick', modifyText);
}

Comment from Mozilla:
There is a drawback to attachEvent, the value of this will be a
reference to the window object instead of the element on which it was
fired.
---------------------------------

Question:
If I attach events like this, how should I handle the this==window (IE)
problem in the modifyText function?
(I only want to get a reference to the element where this particular
event originated.)

I tried the following approach (which works in IE7 and FF3)
Is this a good/safe approach?

function modifyText(e){
var srcElRef = getSrcElement(e);
// do stuff with srcElRef
}

function getSrcElement(e){
if (e.target){
return e.target;
}
if (e.srcElement){
return e.srcElement;
}
alert("could not find srcelement");
}

And should I prepare for the situation where I alert the "could not find
srcelement"?

Thanks for your time.

Regards,
Erwin Moller

--
"There are two ways of constructing a software design: One way is to
make it so simple that there are obviously no deficiencies, and the
other way is to make it so complicated that there are no obvious
deficiencies. The first method is far more difficult."
-- C.A.R. Hoare
 
M

Martin Honnen

Erwin said:
Considering the following code:
[https://developer.mozilla.org/en/DOM/element.addEventListener]

---------------------------------
if (el.addEventListener){
el.addEventListener('click', modifyText, false);
} else if (el.attachEvent){
el.attachEvent('onclick', modifyText);
}

Comment from Mozilla:
There is a drawback to attachEvent, the value of this will be a
reference to the window object instead of the element on which it was
fired.
---------------------------------

Question:
If I attach events like this, how should I handle the this==window (IE)
problem in the modifyText function?
(I only want to get a reference to the element where this particular
event originated.)

The this object is not necessarily the element where the event
originated. If that el element has child (or more generally descendant)
elements then if you click inside the element on a child (or more
generally descendant) element the click event listener is called but the
target (in the W3C DOM) or the srcElement (in the IE event model) in
that case is not the el element but rather the child (or more generally
descendant) element on which you clicked. The W3C DOM model knows a
property currentTarget of the event model which would be the el element
the. Browsers like Mozilla or Opera also set the this object although
that is not required by the W3C DOM. IE's event model does not have any
property corresponding to currentTarget. And as you have found, this is
not set the way it is in Mozilla. You could however use

el.attachEvent('onclick',
function (evt) { modifyText.call(el, evt); });

for IE, that way you would have the el element as the this object when
modifyText is called.
 
E

Erwin Moller

Martin Honnen schreef:
Erwin said:
Considering the following code:
[https://developer.mozilla.org/en/DOM/element.addEventListener]

---------------------------------
if (el.addEventListener){
el.addEventListener('click', modifyText, false);
} else if (el.attachEvent){
el.attachEvent('onclick', modifyText);
}

Comment from Mozilla:
There is a drawback to attachEvent, the value of this will be a
reference to the window object instead of the element on which it was
fired.
---------------------------------

Question:
If I attach events like this, how should I handle the this==window
(IE) problem in the modifyText function?
(I only want to get a reference to the element where this particular
event originated.)

The this object is not necessarily the element where the event
originated. If that el element has child (or more generally descendant)
elements then if you click inside the element on a child (or more
generally descendant) element the click event listener is called but the
target (in the W3C DOM) or the srcElement (in the IE event model) in
that case is not the el element but rather the child (or more generally
descendant) element on which you clicked.

Thank you Martin.

That is a good reason to do it differently indeed.
I got away with it because the elements in question don't have childs,
but that is of course no reason to do it this way.


The W3C DOM model knows a
property currentTarget of the event model which would be the el element
the. Browsers like Mozilla or Opera also set the this object although
that is not required by the W3C DOM. IE's event model does not have any
property corresponding to currentTarget. And as you have found, this is
not set the way it is in Mozilla. You could however use

el.attachEvent('onclick',
function (evt) { modifyText.call(el, evt); });

for IE, that way you would have the el element as the this object when
modifyText is called.

Clear. :)
An obvious, clean solution since I have the element el at hand already.

Thanks a lot Martin.

Regards,
Erwin Moller

--
"There are two ways of constructing a software design: One way is to
make it so simple that there are obviously no deficiencies, and the
other way is to make it so complicated that there are no obvious
deficiencies. The first method is far more difficult."
-- C.A.R. Hoare
 
P

Peter Michaux

   el.attachEvent('onclick',
     function (evt) { modifyText.call(el, evt); });

Martin, do you worry about IE memory leaks? Do you write this sort of
code without any onunload cleanup to break the circular reference
between the element and the handler function?

Peter
 
D

David Mark

Martin, do you worry about IE memory leaks? Do you write this sort of
code without any onunload cleanup to break the circular reference
between the element and the handler function?

Tacking on that destructive workaround is not the answer. Use
patterns that don't leak.
 
E

Eric Bednarz

Peter Michaux said:
Martin, do you worry about IE memory leaks? Do you write this sort of
code without any onunload cleanup to break the circular reference
between the element and the handler function?

Sorry, I’m not Martin. ;-)

IIRC the issue has been fixed (for most cases) as part of a security
update more than a year ago, so IE6 on XP SP3 should be no
problem. Sometimes the best attitude might be “I don’t care (anymore)â€,
especially if it is reasonable to assume that a solution to a minority
problem will hurt others (as onunload does).

For the fun of it, I have collected some empirical data for myself:

Attaching 500 listeners to a document, the above pattern
- does not leak in my IE 6 on a fully up to date XP SP3
- leaks ~ 1 MiB per page refresh in my IE 6 on a fully up to date XP SP2
and ditto Windows 2000

Using His Library for the same task, there appear to be no real leaks on
Windows 2000 (memory increases notably but is released when navigating
away from the test page). Well done.
On XP SP2, on the other hand, every refresh leaks average 3 to 4 MiB
memory, with a peak of 8 MiB (refreshing ~ 20 times total).

So what am I supposed to learn from that? :)
 
D

David Mark

Sorry, I’m not Martin. ;-)

IIRC the issue has been fixed (for most cases) as part of a security
update more than a year ago, so IE6 on XP SP3 should be no
problem. Sometimes the best attitude might be  “I don’t care (anymore)”,
especially if it is reasonable to assume that a solution to a minority
problem will hurt others (as onunload does).

I don't know, I've seen some hellacious leaks in IE7.
For the fun of it, I have collected some empirical data for myself:

Attaching 500 listeners to a document, the above pattern
- does not leak in my IE 6 on a fully up to date XP SP3

Of course, not everyone with IE6 will be up to date.
- leaks ~ 1 MiB per page refresh in my IE 6 on a fully up to date XP SP2
  and ditto Windows 2000
Okay.


Using His Library for the same task, there appear to be no real leaks on
Windows 2000 (memory increases notably but is released when navigating
away from the test page). Well done.

LOL. You mean My Library?
On XP SP2, on the other hand, every refresh leaks average 3 to 4 MiB
memory, with a peak of 8 MiB (refreshing ~ 20 times total).

I'd wager it is unrelated to my event code, which clearly does not
create circular references involving host objects. I'd like to know
exactly what you tested and how you came to your conclusions.
So what am I supposed to learn from that? :)

Sounds like a great opportunity for you to learn, which is why I
posted the code in the first place. ;)
 
D

David Mark

I don't know, I've seen some hellacious leaks in IE7.





Of course, not everyone with IE6 will be up to date.


LOL.  You mean My Library?


I'd wager it is unrelated to my event code, which clearly does not
create circular references involving host objects.  I'd like to know
exactly what you tested and how you came to your conclusions.




Sounds like a great opportunity for you to learn, which is why I
posted the code in the first place.  ;)

Also, as recently discussed in another thread, My Library has the
unload cleanup, which is another indication that whatever you saw was
either a false positive or unrelated to the attached listeners (have
to figure it would also leak in 2000 if that were the case.)

Would like to see the test page (I assume you weren't using my test
page, which introduces too many other variables to be of use here.)
And are you using just the event module or the whole thing?
 
E

Eric Bednarz

David Mark said:
LOL. You mean My Library?

Yes, Your Library. ;-)
I'd wager it is unrelated to my event code, which clearly does not
create circular references involving host objects. I'd like to know
exactly what you tested and how you came to your conclusions.

I knew my test was probably problematic itself, but I used the same one
for three different IE 6 environments, so that was not my primary
concern.

What I did was creating a DIV element, appending it to the DOM,
appending a text node and attaching a click event. In that order, in a
loop with 500 iterations, on the window’s load event.

Not generating the elements client side made things better (rather
unsurpsisingly).

And I used the complete library. I already suspected that this would
matter, too. Kangax recently posted the basic event code and I used that
for an absolute minimum test (correcting the minor error he made). With
this setup, I noticed a much smaller but consistent memory leakage.

After some random testing the ugly truth dawned upon me. It is much
worse than I thought. I through all of the test code out and generated
a javascript file with 500 function declarations that just return
false. No function calls, no DOM access, nothing. Using that ~ 18KiB
file, IE6 was consistently leaking ~200KiB on every (re)load of the
page. Unsurprisingly, in further testing this leakage grew with the file
size (hence the obscene amount when using the complete mylib.js).

The offending system is XP SP2.

I’ll put a test case for that online tomorrow or so, today is some sort
of anniversary to attend to :)
 
D

David Mark

Yes, Your Library. ;-)

Doh! Kidding, of course. It wouldn't surprise me in the least if
*something* leaked in there with IE6. It would surprise me if it is
related to attachListener, so I was interested in your tests.
I knew my test was probably problematic itself, but I used the same one
for three different IE 6 environments, so that was not my primary
concern.

You may be on to something. Just not sure what yet.
What I did was creating a DIV element, appending it to the DOM,
appending a text node and attaching a click event. In that order, in a
loop with 500 iterations, on the window’s load event.
Okay.


Not generating the elements client side made things better (rather
unsurpsisingly).

Well, I find that a bit odd. Did the library play any part in
creating these nodes?
And I used the complete library. I already suspected that this would
matter, too. Kangax recently posted the basic event code and I used that
for an absolute minimum test (correcting the minor error he made). With
this setup, I noticed a much smaller but consistent memory leakage.

The complete library is not going to be a good test case for this. I
was going to suggest the code posted by Kangax.
After some random testing the ugly truth dawned upon me. It is much
worse than I thought. I through all of the test code out and generated
a javascript file with 500 function declarations that just return
false. No function calls, no DOM access, nothing. Using that ~ 18KiB
file, IE6 was consistently leaking ~200KiB on every (re)load of the
page. Unsurprisingly, in further testing this leakage grew with the file
size (hence the obscene amount when using the complete mylib.js).

Yes, I suspected IE6 and XP were to blame. Sounds like the bigger the
script (whatever it holds), the bigger the leak. Pretty bad when MS
can't write a competent browser for their own OS.
The offending system is XP SP2.

Should be locked up. :)
I’ll put a test case for that online tomorrow or so, today is some sort
of anniversary to attend to :)

I guess I'm slightly less interested now, but it would be nice to
document this particular abomination.

I think I've said it here before, but I would never buy a PC with
Windows installed on it again. I can't believe it took me over a
decade to realize that Microsoft was all marketing.
 
E

Eric Bednarz

David Mark said:
Well, I find that a bit odd. Did the library play any part in
creating these nodes?

Not at all.

Oh well. Hopefully sometime this weekend, then.
I guess I'm slightly less interested now,

I guess I just took your word for it ;-)
but it would be nice to
document this particular abomination.

Sure. I would like to know if it’s reproducable (couldn’t find any other
XP SP2 versions so far).
 
R

RobG

Yes, Your Library. ;-)

Of course, "His Library" might indicate delusions of grandeur...

[...]
And I used the complete library. I already suspected that this would
matter, too. Kangax recently posted the basic event code and I used that
for an absolute minimum test (correcting the minor error he made).

Missed that thread so I looked it up:

"Re-enable disabled form elements when user goes 'Back'"
<URL: http://groups.google.com/group/comp.lang.javascript/msg/a318f930c21433d6
The error is a classic, in the block:

else if (window.attachEvent) {
return function(element, eventName, handler) {
eventContexts[contextId++] = element;
var normalizedHandler = getNormalizedHandler(contextId,
handler);
element.attachEvent('on' + eventName, normalizedHandler);
};
}

contextId is incremented after evaluating eventContexts, the next call
uses the incremented value (oops...). It could be pre-incremented, but
that wastes the zero index, so perhaps incrementing it at the bottom
of the block is best - makes it explicit and probably better for
maintenance:

return function(element, eventName, handler) {
eventContexts[contextId] = element;
var normalizedHandler = getNormalizedHandler(contextId, handler);
element.attachEvent('on' + eventName, normalizedHandler);
contextId++;
};
 
D

David Mark

Of course, "His Library" might indicate delusions of grandeur...

[snip]

I'm sure that was meant (hopefully in a joking manner.) The thing
that a lot of people seemed to have missed about that app was that
"My" referred to the person customizing the library (as opposed to
me.) I'm pretty sure I referred to the result as "your library" at
some point in the site.

Oh well, that's probably the *least* of what was missed there.
 
E

Eric Bednarz

David Mark said:
Yes, I suspected IE6 and XP were to blame. Sounds like the bigger the
script (whatever it holds), the bigger the leak. Pretty bad when MS
can't write a competent browser for their own OS.

<http://bednarz.nl/tmp/sieve/>

I’ve made it 5000 functions to make the leakage easier to follow in the
task manager; smaller numbers work as consistent. Having so many
identifiers in the global (or generally same) scope might make things
worse, but as it also leaked heavily with My Library I didn’t bother to
test if that makes a difference.


To summarize:

Symptom: reloading the page consistently leaks memory (in my case 1 - 3
MiB) in IE6 on Windows XP SP2 (to the best of my knowlwdge the system is
as up to date as SP2 can be without upgrading IE to version 7). The
memory is not freed when navigating away from the page.
(And if it is not clear to anyone, the alarming thing is that the
leakage seems to be simply proportional to the size of the script file.)

Not reproducable with IE6 on Windows 2000 (!) and XP SP3.


I would be interested to know if anyone can – or cannot – reproduce that.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top