私のブログから:
カウンターやその他の標準以下のアプローチを使用すると、コードベースがますます読みにくくなり、保守が難しくなるため、コードの機能不全が助長されます。これを達成するための理想的な方法は、イベント駆動型アプローチを使用することです。保守が容易になり、今後のスパゲッティ コードの削減につながります。次のようなものを簡単に実装できます。
//First, we need an object that will contain our 'event domain'
var EventDomain = new function(config,callback){
this.__listeners = {}; //this will store references to functions associated to events
this.on = function(event,listener){ //here, we provide a member that binds
//a 'listener' function to an event string
if (typeof this.__listeners[event] == "undefined"){
this.__listeners[event] = [];
}
this.__listeners[event].push(listener);
};
this.emit = function(event,params){ //here, we provide a member that 'emits' an
//event string, calling any 'listener' functions
//and passing a parameter object
//{param1: val1, param2:val2, paramN, valN}
if(typeof event == "string"){
event = { type: event };
}
if(!event.target){
event.target = this;
}
if(!event.type){
throw new Error("Event object missing 'type' property.");
}
if(this.__listeners[event.type] instanceof Array){
var listeners = this.__listeners[event.type];
for (var i=0, len=listeners.length; i < len; i++){
listeners[i](params);
}
}
};
this.removeListener = function(type, listener){ //here, we provide a member that allows
//us to remove a 'listener' function
//from an event
if(this.__listeners[type] instanceof Array){
var listeners = this.__listeners[type];
for (var i=0, len=listeners.length; i < len; i++){
if (listeners[i] === listener){
listeners.splice(i, 1);
break;
}
}
}
};
this.removeAllListeners = function(type){ //here, we provide a member that allows
//us to remove ALL 'listener' functions
//from an event
if(this.__listeners[type] instanceof Array){
delete this.__listeners[type];
}
};
};
イベント ドメインができたので、それを上記のコード スニペットで使用できます。しかし、最初に、ajax 呼び出しのコントローラーとして機能するオブジェクトを作成しましょう。
var AjaxController = new function(){
var counter; //create a private member called counter
this.onLoad = function(fn){ //here, we provide a member to specify what to do
//when ajax requests begin
EventEmitter.on('ajax_loading',(function(fn){ //bind 'ajax_loading' event to an
//ajax loading indicator
return function(){ //yet another closure
if(counter<1){ //obviously, we only want to do something on the first
//load, not every single time. Otherwise, you'll end
//end up trying to show the exact same loading animation
//for each ajax call
fn();
}
counter++;
};
})(fn));
};
this.onComplete = function(fn){ //here we provide a member to specify what to do
//when ALL ajax requests have finished
EventEmitter.on('ajax_complete',(function(fn){ //bind the 'ajax_complete' event
//to a loading indicator
return function(){ //yet another closure
counter--; //decrement concurrent loading
if(counter<1){ //its only finished once the counter is 0!
fn();
}
}
})(fn));
};
var constructor = function(){ //good object oriented programming uses constructors!
counter = 0;
//Now, lets overload the original $.ajax method to provide functionality
//for our event driven approach
$.ajax = (function(ajax){ //this is called a 'closure'.
//We pass it the original function and it wraps and
//returns it, overloading the original method
function overloadAjax(params){ //this is our overloading function
if(params.success){ //if there is a success parameter passed
//to the ajax call, overload that as well
//to emit the 'ajax_complete' event
params.success = (function(success){
function overloadSuccess(data){
EventDomain.emit('ajax_complete');
success(data);
}
return overloadSuccess; //return and overload success
})(params.success);
}
EventDomain.emit('ajax_loading'); //emit the 'ajax_loading' event
//for each ajax call
ajax(params);
}
return overloadAjax; //here we return 'overload' back to $.ajax, overloading
//the original
})($.ajax);
}
constructor(); //we call the constructor after all members have been prototyped
}
再利用可能な素敵な ajax ローダー ツールキットを作成したので、それを使用してみましょう。
AjaxController.onLoad(function(){
//put some code here to do DOM manipulation to add a loader, or however you
//want to 'indicate' ajax loading
});
AjaxController.onComplete(function(){
//put some code here to do some DOM manipulation to remove your loader, or however
//you want to 'indicate' that ajax loading is complete
});
今、それはうまくいきます:
$("#search_building").on("change blur", function () {
var building = $("#search_building").val();
var room = $("#search_room").val();
var dept = $("#dept").val();
var dataString = 'room=' + room + '&' + 'building=' + building + '&' + 'dept=' + dept;
$.ajax({
type: "POST",
url: "process_building.php",
data: dataString,
cache: false,
success: function (html) {
$('#search_room').html(html);
}
});
$.ajax({
type: "POST",
url: "process_timetableMon.php",
data: dataString,
cache: false,
success: function (html) {
$('#grid2_mon').html(html);
}
});
$.ajax({
type: "POST",
url: "process_timetableTue.php",
data: dataString,
cache: false,
success: function (html) {
$('#grid2_tue').html(html);
}
});
$.ajax({
type: "POST",
url: "process_timetableWed.php",
data: dataString,
cache: false,
success: function (html) {
$('#grid2_wed').html(html);
}
});
$.ajax({
type: "POST",
url: "process_timetableFri.php",
data: dataString,
cache: false,
success: function (html) {
$('#grid2_wed').html(html);
}
});
$.ajax({
type: "POST",
url: "process_roomList.php",
data: dataString,
cache: false,
success: function (html) {
$('#list2').html(html);
}
});
});
フロントエンドでイベント駆動型プログラミングとオブジェクト指向プログラミングを組み合わせることの大きな利点は、開発者がより実際のコンテンツ作成に専念でき、問題解決が少なくなることです。再利用可能なフレームワークを作成するには、最初は時間がかかりますが、時間と品質の面で飛躍的なメリットがあります。これらの概念についてさらにサポートが必要な場合は、お気軽にメールでお問い合わせください: rhyneandrew@gmail.com. 無料で教えていただけると嬉しいです(;_;)