在設計JavaScript xxsdk的時候考慮到能讓調用者參與到工作流程中來,開始用了回調函數。如下:
this.foo = function(args,callbackFn) {
//do something
//then if callbackFn is a function
callbackFn();
};
或者在初始化的傳入config。
function SDK(config) {
var configs = {
onInit: function() {
},
onFoo: function () {
},
// on....
};
//合並參數
configs = $.extend(configs, config);
this.foo = function (args) {
//do something
configs.onFoo();
};
}
但問題來了,隨著函數越多,第一種方式就顯得很煩,每個方法的參數後面要跟一個或者多個回調函數,代碼顯得不干淨,而且只有用戶調用的時候才會執行回調,對於沒有暴露給用戶的方法就用不上。第二種方式,函數越多,config就越長,構造代碼顯得難看,另一方面就是一個方法只會觸發一個回調。最後使用了下面的方式
先定義一個事件管理器,主要思路是讓每一個事件類型對應一個回調列表,這樣可以讓外部對同一個事件關聯多次。取消某個關聯就是在該事件類型的函數列表中移除某個回調函數。觸發就是把列表中函數全部執行一遍。當然還帶上了參數。
var eventManger = {
handlers: {},
//類型,綁定事件
addHandler:function(type,handler) {
if (typeof this.handlers[type] == "undefined") {
this.handlers[type] = [];//每個事件都可以綁定多次
}
this.handlers[type].push(handler);
},
removeHandler:function(type, handler) {
var events = this.handlers[type];
for (var i = 0, len = events.length; i < len; i++) {
if (events[i] == handler) {
events.splice(i, 1);
break;
}
}
},
trigger: function (type) {
if (this.handlers[type] instanceof Array) {
var handlers = this.handlers[type];
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0, len = handlers.length; i < len; i++) {
handlers[i].apply(null, args);
}
}
}
};
然後在sdk中公布關聯和移除的方法:
//給外部綁定事件
this.on = function(type, event) {
eventManger.addHandler(type,event);
};
//移除事件
this.off = function(type, event) {
eventManger.removeHandler(type, event);
};
在執行的過程中分別觸發事件:
this.init = function() {
//do init
eventManger.trigger('init');
};
this.start = function() {
//do start
eventManger.trigger('start');
};
this.connect = function() {
eventManger.trigger('connect');
};
this.messages = function() {
var msgs = [];
msgs.push("你好嗎");
msgs.push("我很好");
eventManger.trigger('messages',msgs);
};
this.disconnect = function() {
eventManger.trigger('disconnect');
};
那用戶在使用的時候就比較方便了。
//綁定connect
sdk.on('connect', function () {
console.log('connect');
});
//綁定messages
sdk.on('messages', function (data) {
if (!data) return;
if (data instanceof Array) {
for (var i = 0; i < data.length; i++) {
console.log(data[i]);
}
} else {
console.log(data);
}
});
還可以先綁定,移除再綁定。
var oninit = function() {
console.log('init...');
};
sdk.on('init', oninit);
sdk.on('init', function () {
console.log('other init');
});
sdk.off('init', oninit);
sdk.init();
全部代碼:
function SDK() {
var eventManger = {
handlers: {},
//類型,綁定事件
addHandler:function(type,handler) {
if (typeof this.handlers[type] == "undefined") {
this.handlers[type] = [];//每個事件都可以綁定多次
}
this.handlers[type].push(handler);
},
removeHandler:function(type, handler) {
var events = this.handlers[type];
for (var i = 0, len = events.length; i < len; i++) {
if (events[i] == handler) {
events.splice(i, 1);
break;
}
}
},
trigger: function (type) {
if (this.handlers[type] instanceof Array) {
var handlers = this.handlers[type];
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0, len = handlers.length; i < len; i++) {
handlers[i].apply(null, args);
}
}
}
};
//給外部綁定事件
this.on = function(type, event) {
eventManger.addHandler(type,event);
};
//移除事件
this.off = function(type, event) {
eventManger.removeHandler(type, event);
};
this.init = function() {
//do init
eventManger.trigger('init');
};
this.start = function() {
//do start
eventManger.trigger('start');
};
this.connect = function() {
eventManger.trigger('connect');
};
this.messages = function() {
var msgs = [];
msgs.push("你好嗎");
msgs.push("我很好");
eventManger.trigger('messages',msgs);
};
this.disconnect = function() {
eventManger.trigger('disconnect');
};
this.autoRun = function() {
this.init();
this.start();
this.connect();
this.messages();
this.disconnect();
};
}
var sdk = new SDK();
var oninit = function() {
console.log('init...');
};
sdk.on('init', oninit);
sdk.on('start', function () {
console.log('start');
});
sdk.on('connect', function () {
console.log('connect');
});
sdk.on('messages', function (data) {
if (!data) return;
if (data instanceof Array) {
for (var i = 0; i < data.length; i++) {
console.log(data[i]);
}
} else {
console.log(data);
}
});
sdk.on('disconnect', function () {
console.log('disconnect');
});
sdk.autoRun();
sdk.on('init', function () {
console.log('other init');
});
sdk.off('init', oninit);
sdk.init();
View Code
執行結果:

小結:事件的處理方式更加簡潔且更有擴展性。jquery的事件機制沒有將事件監聽函數綁定到DOM元素上,而是基於數據緩存模塊來管理的。這裡借鑒了下,對同一事件類型type的所有監聽對象handleObj構成監聽對象數組handles。因為沒有涉及到dom操作,所以相對也簡單些。