日期:2014-05-16  浏览次数:20465 次

关于seajs模块间相互依赖调用的解耦问题

前端密集型项目中如果数据同步的量很大,往往需要对于多个组件进行数据同步,其中必会导致几个组件之间的互相依赖调用,在seajs中递归嵌套的调用组件会引起循环引用导致内存泄露。

?

比如有这样两个模块组件:

?

//@file : module/buddy/friend-in-group/friend-in-group.js
define(function(require, exports, module){
	var $ = require('lib/jquery.js'),
		_ = require('lib/underscore.js'),
		friend = require('module/buddy/add-friend/add-friend');
	
	var _addFriend = function(){
		// Some logic here
	};
	
	var _removeFriend = function(uid){
		// Some logic here
	};
	
	exports.addFriend = function(uid){
		// Some logic here
		_addFriend(uid,false);
	};
	
	exports.removeFriend = function(uid){
		// Some logic here
		_removeFriend(uid,false);
	};
	
	exports.init = function(){
		// Some logic here
		friend.add();
	}

});

?

//@file : module/buddy/add-friend/add-friend.js
define(function(require, exports, module){
	var $ = require('lib/jquery.js'),
		_ = require('lib/underscore.js'),
		fig = require('module/buddy/friend-in-group/friend-in-group');
	
	var itemClickAction = function(){
		var increase; 
		// Some logic here
		if(increase === 1){
			fig.addFriend(uid,gid);
		}else{
			fig.removeFriend(uid,gid);
		}
	};
	
	exports.add = function(){
		// Some logic here
		itemClickAction();
	}

});

这样两个模块组件,friend-in-group组件 和 add-friend组件,friend-in-group组件由于一些UI需求需要调用add-friend组件,而friend-in-group组件暴露的两个方法addFriend和removeFriend是用于其他模块同步数据时用的,正好add-friend其中当执行itemClickAction方法时由于用户的动作会产生数据同步操作需要调用friend-in-group暴露的这两个方法。这样就产生了闭包的循环调用,seajs处会直接报错。如何对这两个模块进行解耦呢?如果是单例模式的模块其实可以直接采用拟事件注册的方法在内部解决,但是比如说add-friend这个模块是非单例且重用度很大呢?这个问题在项目中的确是个麻烦事。

?

参考了backbone模块间通信模式后可以有中间件进行方法注入负责模块间通信。引入中间件:

?

define(function(require, exports, module){
	var $ = require('lib/jquery');
	var _ = require('lib/underscore');
	var events = {};
	
	exports.subscribe = function(type,fn,arg){
		if(!events[type]){
			events[type] = {};
		}
		events[type] = {
			fn:fn,
			arg:arg
		};
	};

	exports.unsubscribe = function(type){
		if(!events[type] || !type ){
			return false;
		}
		if(!!events[type]){
			events[type] = {};
			return true;
		}
		return false;
	};

	exports.fire = function(type,data){
		if(events[type]){
			events[type].fn(data,events[type].arg);
		}
	};
	
});

这个模块首先是不会引入要解耦两方模块的任何一方,降低了耦合性。主要的是一个暴露的注册方法,和一个触发器方法,这样可以在friend-in-group方法中向中间件注入addFriend和removeFriend方法再在add-friend组件中进行触发,其中并不会形成递归的循环调用。

?

?

//@file : module/buddy/friend-in-group/friend-in-group.js
define(function(require, exports, module){
	var $ = require('lib/jquery.js'),
		_ = require('lib/underscore.js'),
		fmw = require('module/buddy/friend-in-group/friend-middleware'),
		friend = require('module/buddy/add-friend/add-friend');
	
	var _addFriend = function(){
		// Some logic here
	};
	
	var _removeFriend = function(uid){
		// Some logic here
	};
	
	var subscribeEvent = function(){
		
		fmw.subscribe('add',function(data,arg){
			// Some logic here
			_addFriend(uid,false);
		},[currentGroupId]);
		
		fmw.subscribe('remove',function(data,arg){
			// Some logic here
			_removeFriend(uid);
		},[currentGroupId]);
	}
	
	exports.init = function(){
		// Some logic here
		friend.add();
	}

});
//@file : module/buddy/friend-in-group/friend-in-group.js
define(function(require, exports, module){
	var $ = require('lib/jquery.js'),
		_ = require('lib/underscore.js'),
		fmw = require('module/buddy/friend-in-group/friend-middleware'),
		friend = require('module/buddy/add-friend/add-friend');
	
	var _addFriend = function(){
		// Some logic here
	};
	
	var _removeFriend = function(uid){