Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
// сам класс:
function _WithEvent(types) {
var listeners = {}; // список слушателей, разделенный по типам событий
for (var i=0, l=types.length; i<l; i++) {
listeners[types[i]] = [];
}
this.addListener = function(type, fn, args, context) {
// добавляем случателя на события type:
// fn - исполняемя функция, args - 2й+ аргументы, context - this в исполняемом методе
listeners[type].push( new Listener(fn, args, context) );
};
this.fireEvent = function(type, data) {
// запускаем событие type, все св-ва из data перекочуют в первый аргумент
var evt = new Event(type, data);
for (var i=0, l=listeners[type].length; i<l; i++) {
if (evt.stoped) break;
evt.lastRet.push( listeners[type][i].fire(evt) );
}
return !evt.stoped;
};
function Listener(fn, args, context) {
// класс слушателей
this.fire = function(evt) {
try {
return fn.apply(context || this, [evt].concat(args || []));
} catch(er) {
return;
}
};
}
function Event(type, data) {
// класс события
if (typeof(data)=="object") {
for (var key in data) {
this[key] = data[key];
}
}
this.type = type;
this.lastRet = [];
this.stoped = false;
this.stop = function() {
this.stoped = true;
};
}
}
// и пример использования:
function Q(map) {
_WithEvent.call(this, [ "q", "w" ]);
var countQ = 0, countW = 0;
this.q = function() {
// запускаем событие "q" и смотрим (!success), не застопили его
var success = this.fireEvent("q", {curValue: countQ, nextValue:countQ+1});
if (!success) return;
// если не застопили
countQ++;
};
this.w = function() {
// аналогично q
var success = this.fireEvent("w", {curValue: countW, nextValue:countW+1, q: countQ});
if (!success) return;
countW++;
};
}
// подписываемся
var obj = new Q();
obj.addListener("q", myAlert);
obj.addListener("w", onW);
obj.addListener("w", myAlert);
obj.q();
obj.w(); // событие стопится, т.к. evt.q==1
obj.q();
obj.w();
function myAlert(evt) {
alert(evt.type +": "+ evt.curValue +" >> "+ evt.nextValue);
}
function onW(evt) {
if (evt.q==1) evt.stop();
}
this.getNextListener = function(listeners) {
// не экономно, зато написал быстро :)
for (var i=0, l=listeners.length; i<l; i++) {
if (!indexOf(this.firedFor, listeners[i])) return listeners[i];
}
};
function indexOf(array, search) {
for (var i=0, l=array.length; i<l; i++) {
if (array[i]==search) return true;
}
}
var evt = new Event(type, data);
var listener = true, listenersType=listeners[type];
while(listener) {
if (evt.stoped) break;
listener = evt.getNextListener(listenersType);
if (!listener) break;
evt.firedFor.push( listener );
evt.lastRet.push( listener.fire(evt) );
}
return !evt.stoped;
обработка XRH до наступления readyState=4.
Похожего результата можно было бы достичь и с помощью jquery trigger/bind. Тогда бы вместо подписки, вешали бы bind
Практически все и вся завязано на события.
CM.Event = {
addListener: function(obj, type, fn, context) {
obj._events = obj._events || {};
obj._events[type] = obj._events[type] || [];
obj._events[type].push({
action: fn,
context: context
});
},
hasListeners: function(obj, type) {
return !!(obj._events && obj._events[type]);
},
removeListener: function(obj, type, fn, context) {
if (!this.hasListeners(obj, type)) { return; }
for (var i = 0; i < obj._events[type].length; i++) {
if ((obj._events[type][i].action == fn) &&
(!context || (obj._events[type][i].context == context))) {
obj._events[type] = obj._events[type].slice(0, i).concat(obj._events[type].slice(i + 1));
return;
}
}
},
fire: function(obj, type) {
if (!this.hasListeners(obj, type)) { return; }
var args = Array.prototype.slice.call(arguments, 2),
listeners = [], i;
for (i = 0; i < obj._events[type].length; i++) {
listeners[i] = obj._events[type][i];
}
for (i = 0; i < listeners.length; i++) {
listeners[i].action.apply(listeners[i].context || obj, args);
}
}
};
function handlerFn(arg1, arg2, ...) { ... }
...
CM.Event.addListener(exampleObj, 'exampleevent', handlerFn, this);
...
CM.Event.fire(exampleObj, 'exampleevent', arg1, arg2, ...);
Используем паттерн Наблюдатель(Observer) для создания индикатора выполнения процесса на Javascript