Skip to content

Commit

Permalink
Switch to a different strategy for event handler garbage collection. …
Browse files Browse the repository at this point in the history
…Store references to elements instead of searching the entire document. [#10 state:resolved]
  • Loading branch information
savetheclocktower committed Apr 18, 2008
1 parent 3d27a63 commit 6ff8485
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
@@ -1,3 +1,5 @@
* Switch to a different strategy for event handler garbage collection. Store references to elements instead of searching the entire document. (jddalton, kangax, Andrew Dupont)

* Add event cleanup on Element#update and Element#replace so that replaced content does not leak memory. (jddalton, Andrew Dupont)

* Loop through all elements and remove all handlers on page unload. IE needs this in order to prevent memory leaks. (kangax, jddalton, Andrew Dupont)
Expand Down
16 changes: 2 additions & 14 deletions src/dom.js
Expand Up @@ -878,23 +878,11 @@ else if (Prototype.Browser.IE) {
});
})(Element._attributeTranslations.read.values);

// Wrap Element#update and Element#replace to clean up event handlers on
// Wrap Element#update to clean up event handlers on
// newly-removed elements. Prevents memory leaks in IE.
Element._purgeObservers = function(element, includeRoot) {
Element.select(element, '*').each(Event.stopObserving);
if (includeRoot === true) Event.stopObserving(element);
};

Element.Methods.update = Element.Methods.update.wrap(
function(proceed, element, contents) {
Element._purgeObservers(element, false);
return proceed(element, contents);
}
);

Element.Methods.replace = Element.Methods.replace.wrap(
function(proceed, element, contents) {
Element._purgeObservers(element, true);
Element.select(element, '*').each(Event.stopObserving);
return proceed(element, contents);
}
);
Expand Down
21 changes: 15 additions & 6 deletions src/event.js
Expand Up @@ -148,8 +148,11 @@ Object.extend(Event, (function() {
var cache = Event.cache;

function getEventID(element) {
// Event ID is stored as the 0th index in a one-item array so that it
// won't get copied to a new node when cloneNode is called.
if (element._prototypeEventID) return element._prototypeEventID[0];
arguments.callee.id = arguments.callee.id || 1;

return element._prototypeEventID = [++arguments.callee.id];
}

Expand All @@ -168,7 +171,12 @@ Object.extend(Event, (function() {
}

function createWrapper(element, eventName, handler) {
var id = getEventID(element);
var id = getEventID(element), _c = getCacheForID(id);

// Attach the element itself onto its cache entry so we can retrieve it for
// cleanup on page unload.
if (!_c.element) _c.element = element;

var c = getWrappersForEventName(id, eventName);
if (c.pluck("handler").include(handler)) return false;

Expand Down Expand Up @@ -200,16 +208,17 @@ Object.extend(Event, (function() {
// Loop through all elements and remove all handlers on page unload. IE
// needs this in order to prevent memory leaks.
function purgeListeners() {
var all = document.getElementsByTagName('*');
for (var i, node; node = all[i]; i++) {
if (node.nodeType !== Node.ELEMENT_NODE) continue;
Element.stopObserving(node);
var element, entry;
for (var i in Event.cache) {
entry = Event.cache[i];
Event.stopObserving(entry.element);
entry.element = null;
}
}

function onStop() {
document.detachEvent('onstop', onStop);
destroyCache();
purgeListeners();
}

function onBeforeUnload() {
Expand Down

0 comments on commit 6ff8485

Please sign in to comment.