IE6/7的事件注册,闭包导致内存泄露问题

IE6/7由于使用引用计数,容易产生内存泄露问题。

事件注册,由于容易使用闭包,导致问题产生:

//循环引用:element的事件函数(闭包)可以指向element。
var addListener = function (element, eventName, handler) {
  element.attachEvent('on' + eventName, function () {
      handler.call(element, window.event);
  });
};

一种处理的方式,就是先把事件函数存起来,在页面离开的时候,进行事件的移除,解除循环引用。

var register = [];
function createObj(el,fn,name){
	return {
		el: el,
		fn: function(e){
			fn.call(el,e||window.event);
		},
		eventName: name
	};
}
var addListener = function (element, eventName, handler) {
    var obj = createObj(element,handler,eventName);
    element.attachEvent('on' + eventName,obj.fn);
    register.push(obj);
};
function cleanupListeners(){
	for(var i=0; i < register.length;i++){
		var item = register[i];
		item.el.detachEvent('on' + item.eventName,item.fn);
		register[i] = null;
	}
}
window.attachEvent('onunload', cleanupListeners);

如果嫌这种方式可能带来一些麻烦,譬如onunload事件的影响,我们考虑,重新设计事件注册函数,一开始,就避开闭包的产生:(这里的代码,只是作为思路演示之用。)

ar register = [],
	fns = {},
	els = {};
var getUid = (function (){
	var id = 0;
	return function(){
		return "_uid_" + id++;
	}
})();
function setElUid(el){
	el.uid = getUid();
	return el;
}
function getElByUid(uid){
	return els[uid];
}
function createFn(uid,fn){
	fns[uid] = function(e){
		fn.call(getElByUid(uid),e||window.event);
	};
	return fns[uid];
}
function createObj(el,fn,name){
	setElUid(el);
	return {
		el: el,
		fn: createFn(el.uid,fn),
		name: name
	};
}
var addListener = function (element, eventName, handler) {
    var obj = createObj(element,handler,eventName);
    element.attachEvent('on' + eventName,obj.fn);
    register.push(obj);
};

相关推荐