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();
	}

});
このような2つのモジュール・コンポーネント、friend-inn-groupコンポーネントとadd-friendコンポーネント、friend-inn-groupコンポーネントは、いくつかのUIニーズのために、add-friendコンポーネントを呼び出す必要がありますが、friend-inn-groupコンポーネントが露出している2つの方法addFriendとremoveFriendは、他のモジュールのデータを同期するために使用されます.ちょうどadd-friendでは、itemClickAction方法を実行すると、ユーザの動作によってデータ同期動作が発生するので、friend-i-group露出を呼び出す2つの方法が必要である.このように、クローズドの循環呼び出しが発生しました.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);
		}
	};
	
});
このモジュールは、まず、2つのモジュールを結合するいずれかの一方を導入することなく、結合を低減する.主なのは露出された登録方法とフリップフロップ方法であり、これはfriend-inn-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){
		// 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(){
		subscribeEvent();
		friend.add();
	}

});
 
 
上のコードのように方法の注入と方法のトリガを行い、friend-inn-groupにaddとremoveを登録する方法イベントは、add-friendで方法イベントのトリガを行います.subscribevent方法では、匿名方法を中間モジュールに転送し、この匿名関数は、argに登録コンポーネントの着信データを保存し、パラメータdata
モジュール側の着信パラメータをトリガし、登録モジュール側でこのモジュールのプライベート関数を参照することは、この匿名関数のクローズド・ロール範囲を登録モジュール内部に拡張することに相当する.このようにして、イベントをトリガするときにモジュールを登録するすべての参照状態を保持することができる.デカップリングの効果を発揮した.