Skip to content

Instantly share code, notes, and snippets.

@dev4design
Last active May 30, 2022 02:42
Show Gist options
  • Save dev4design/0af8feb0d709003b1841b3b251eac1ec to your computer and use it in GitHub Desktop.
Save dev4design/0af8feb0d709003b1841b3b251eac1ec to your computer and use it in GitHub Desktop.
class EventBus {
constructor() {
// 이벤트 리스트 초기화
this.eventObject = {};
}
// 이벤트 발행
publish(eventName) {
// 현재 이벤트의 모든 콜백함수 호출
const callbackList = this.eventObject[eventName];
if (!callbackList) return console.warn(eventName + " not found!");
// 콜백함수 실행
for (let callback of callbackList) {
callback();
}
}
// 이벤트 구독
subscribe(eventName, callback) {
// 이벤트 초기화
if (!this.eventObject[eventName]) {
this.eventObject[eventName] = [];
}
// 구독자가 실행할 콜백함수 저장
this.eventObject[eventName].push(callback);
}
}
// 테스트
const eventBus = new EventBus();
// eventX 이벤트 구독
eventBus.subscribe("eventX", () => {
console.log("Module A");
});
eventBus.subscribe("eventX", () => {
console.log("Module B");
});
eventBus.subscribe("eventX", () => {
console.log("Module C");
});
// eventX 이벤트 발행
eventBus.publish("eventX");
// 결과
> Module A
> Module B
> Module C
class EventBus {
constructor() {
this.eventObject = {};
// 콜백함수 목록의 id 멤버변수
this.callbackId = 0;
}
publish(eventName, ...args) {
const callbackObject = this.eventObject[eventName];
if (!callbackObject) return console.warn(eventName + " not found!");
for (let id in callbackObject) {
// 아이디를 가진 콜백함수 실행
callbackObject[id](...args);
}
}
subscribe(eventName, callback) {
if (!this.eventObject[eventName]) {
// 삭제 효율을 높이기 위해 배열에서 객체 구조로 변경
this.eventObject[eventName] = {};
}
// 다음 콜백함수 사용을 위해 id를 증가
const id = this.callbackId++;
// 아이디와 함께 콜백함수 저장
this.eventObject[eventName][id] = callback;
// 구독 취소를 위한 내부 함수 생성
const unSubscribe = () => {
// 이 구독자의 콜백함수 삭제
delete this.eventObject[eventName][id];
// 이 이벤트에 구독자가 없으면 해당 이벤트 삭제
if (Object.keys(this.eventObject[eventName]).length === 0) {
delete this.eventObject[eventName];
}
};
return { unSubscribe };
}
}
// 테스트
const eventBus = new EventBus();
// 구독
eventBus.subscribe("eventX", (obj, num) => {
console.log("Module A", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
console.log("Module B", obj, num);
});
const subscriberC = eventBus.subscribe("eventX", (obj, num) => {
console.log("Module C", obj, num);
});
// 발행
eventBus.publish("eventX", { msg: "EventX published!" }, 1);
// Module C 구독 취소
subscriberC.unSubscribe();
// eventX 재발행. 이후부터 module C는 이벤트를 받지 않음
eventBus.publish("eventX", { msg: "EventX published again!" }, 2);
// output
> Module A {msg: 'EventX published!'} 1
> Module B {msg: 'EventX published!'} 1
> Module C {msg: 'EventX published!'} 1
> Module A {msg: 'EventX published again!'} 2
> Module B {msg: 'EventX published again!'} 2
class EventBus {
constructor() {
this.eventObject = {};
this.callbackId = 0;
}
publish(eventName, ...args) {
const callbackObject = this.eventObject[eventName];
if (!callbackObject) return console.warn(eventName + " not found!");
for (let id in callbackObject) {
callbackObject[id](...args);
// 한번만 구독한 경우 해당 콜백함수를 제거
if (id[0] === "d") {
delete callbackObject[id];
}
}
}
subscribe(eventName, callback) {
if (!this.eventObject[eventName]) {
this.eventObject[eventName] = {};
}
const id = this.callbackId++;
this.eventObject[eventName][id] = callback;
const unSubscribe = () => {
delete this.eventObject[eventName][id];
if (Object.keys(this.eventObject[eventName]).length === 0) {
delete this.eventObject[eventName];
}
};
return { unSubscribe };
}
// 한번만 구독을 위한 메서드
subscribeOnce(eventName, callback) {
if (!this.eventObject[eventName]) {
this.eventObject[eventName] = {};
}
// 한번만 구독할 콜백함수 마크
const id = "d" + this.callbackId++;
this.eventObject[eventName][id] = callback;
const unSubscribe = () => {
delete this.eventObject[eventName][id];
if (Object.keys(this.eventObject[eventName]).length === 0) {
delete this.eventObject[eventName];
}
};
return { unSubscribe };
}
// 이벤트 제거
clear(eventName) {
// 매개변수로 이름이 제공되지 않으면 모든 이벤트 제거
if (!eventName) {
this.eventObject = {};
return;
}
// 지정된 이름의 이벤트 제거
delete this.eventObject[eventName];
}
}
// 테스트
const eventBus = new EventBus();
// eventX 구독
eventBus.subscribe("eventX", (obj, num) => {
console.log("Module A", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
console.log("Module B", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
console.log("Module C", obj, num);
});
// eventX 발행
eventBus.publish("eventX", { msg: "EventX published!" }, 1);
// eventX 이벤트 제거
eventBus.clear("eventX");
// eventX 재발행. eventX에 대한 이벤트가 제거되어 모든 모듈에서 이벤트를 수신할 수 없다
eventBus.publish("eventX", { msg: "EventX published again!" }, 2);
// output
> Module A {msg: 'EventX published!'} 1
> Module B {msg: 'EventX published!'} 1
> Module C {msg: 'EventX published!'} 1
> eventX not found!
class EventBus {
constructor() {
this.eventObject = {};
this.callbackId = 0;
}
publish(eventName, ...args) {
const callbackObject = this.eventObject[eventName];
if (!callbackObject) return console.warn(eventName + " not found!");
for (let id in callbackObject) {
callbackObject[id](...args);
// 한번만 구독한 경우 해당 콜백함수를 제거
if (id[0] === "d") {
delete callbackObject[id];
}
}
}
subscribe(eventName, callback) {
if (!this.eventObject[eventName]) {
this.eventObject[eventName] = {};
}
const id = this.callbackId++;
this.eventObject[eventName][id] = callback;
const unSubscribe = () => {
delete this.eventObject[eventName][id];
if (Object.keys(this.eventObject[eventName]).length === 0) {
delete this.eventObject[eventName];
}
};
return { unSubscribe };
}
// 한번만 구독을 위한 메서드
subscribeOnce(eventName, callback) {
if (!this.eventObject[eventName]) {
this.eventObject[eventName] = {};
}
// 한번만 구독할 콜백함수 마크
const id = "d" + this.callbackId++;
this.eventObject[eventName][id] = callback;
const unSubscribe = () => {
delete this.eventObject[eventName][id];
if (Object.keys(this.eventObject[eventName]).length === 0) {
delete this.eventObject[eventName];
}
};
return { unSubscribe };
}
}
// 테스트
const eventBus = new EventBus();
// eventX 구독
eventBus.subscribe("eventX", (obj, num) => {
console.log("Module A", obj, num);
});
eventBus.subscribeOnce("eventX", (obj, num) => {
console.log("Module B", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
console.log("Module C", obj, num);
});
// eventX 발행
eventBus.publish("eventX", { msg: "EventX published!" }, 1);
// eventX 재발행. module B는 한번만 구독에 의해 콜백함수 실행되지 않음
eventBus.publish("eventX", { msg: "EventX published again!" }, 2);
// output
> Module A {msg: 'EventX published!'} 1
> Module C {msg: 'EventX published!'} 1
> Module B {msg: 'EventX published!'} 1
> Module A {msg: 'EventX published again!'} 2
> Module C {msg: 'EventX published again!'} 2
class EventBus {
constructor() {
this.eventObject = {};
}
// 이벤트 발행: Rest 파라미터를 사용해 추가 매개변수 전달
publish(eventName, ...args) {
const callbackList = this.eventObject[eventName];
if (!callbackList) return console.warn(eventName + " not found!");
for (let callback of callbackList) {
// 매개변수와 함께 콜백함수 실행
callback(...args);
}
}
// 이벤트 구독
subscribe(eventName, callback) {
if (!this.eventObject[eventName]) {
this.eventObject[eventName] = [];
}
this.eventObject[eventName].push(callback);
}
}
// 테스트
const eventBus = new EventBus();
// 구독
eventBus.subscribe("eventX", (obj, num) => {
console.log("Module A", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
console.log("Module B", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
console.log("Module C", obj, num);
});
// 발행
eventBus.publish("eventX", { msg: "EventX published!" }, 1);
// 결과
> Module A {msg: 'EventX published!'} 1
> Module B {msg: 'EventX published!'} 1
> Module C {msg: 'EventX published!'} 1
interface ICallbackList {
[id: string]: Function;
}
interface IEventObject {
[eventName: string]: ICallbackList;
}
interface ISubscribe {
unSubscribe: () => void;
}
interface IEventBus {
publish<T extends any[]>(eventName: string, ...args: T): void;
subscribe(eventName: string, callback: Function): ISubscribe;
subscribeOnce(eventName: string, callback: Function): ISubscribe;
clear(eventName: string): void;
}
class EventBus implements IEventBus {
private _eventObject: IEventObject;
private _callbackId: number;
constructor() {
// 이벤트 리스트 초기화
this._eventObject = {};
// 콜백함수 목록의 id 멤버변수
this._callbackId = 0;
}
// publish event
publish<T extends any[]>(eventName: string, ...args: T): void {
// 현재 이벤트의 모든 콜백함수 호출
const callbackObject = this._eventObject[eventName];
if (!callbackObject) return console.warn(eventName + " not found!");
// 각 콜백함수 실행
for (let id in callbackObject) {
// 매개변수와 함께 콜백함수 실행
callbackObject[id](...args);
// 한번만 구독한 경우 해당 콜백함수를 제거
if (id[0] === "d") {
delete callbackObject[id];
}
}
}
// Subscribe to events
subscribe(eventName: string, callback: Function): ISubscribe {
// 이벤트 구독
if (!this._eventObject[eventName]) {
// 삭제 효율을 높이기 위해 배열에서 객체 구조로 변경
this._eventObject[eventName] = {};
}
// 다음 콜백함수 사용을 위해 id를 증가
const id = this._callbackId++;
// 아이디와 함께 콜백함수 저장
this._eventObject[eventName][id] = callback;
// 구독 취소를 위한 내부 함수 생성
const unSubscribe = () => {
// 이 구독자의 콜백함수 삭제
delete this._eventObject[eventName][id];
// 이 이벤트에 구독자가 없으면 해당 이벤트 삭제
if (Object.keys(this._eventObject[eventName]).length === 0) {
delete this._eventObject[eventName];
}
};
return { unSubscribe };
}
// 한번만 구독
subscribeOnce(eventName: string, callback: Function): ISubscribe {
if (!this._eventObject[eventName]) {
this._eventObject[eventName] = {};
}
// 한번만 구독할 콜백함수 마크
const id = "d" + this._callbackId++;
this._eventObject[eventName][id] = callback;
const unSubscribe = () => {
delete this._eventObject[eventName][id];
if (Object.keys(this._eventObject[eventName]).length === 0) {
delete this._eventObject[eventName];
}
};
return { unSubscribe };
}
// 이벤트 제거
clear(eventName: string): void {
// 매개변수로 이름이 제공되지 않으면 모든 이벤트 제거
if (!eventName) {
this._eventObject = {};
return;
}
/// 지정된 이름의 이벤트 제거
delete this._eventObject[eventName];
}
}
// 테스트
interface IObj {
msg: string;
}
type PublishType = [IObj, number];
const eventBus = new EventBus();
// eventX 구독
eventBus.subscribe("eventX", (obj: IObj, num: number, s: string) => {
console.log("Module A", obj, num);
});
eventBus.subscribe("eventX", (obj: IObj, num: number) => {
console.log("Module B", obj, num);
});
eventBus.subscribe("eventX", (obj: IObj, num: number) => {
console.log("Module C", obj, num);
});
// eventX 발행
eventBus.publish("eventX", { msg: "EventX published!" }, 1);
// eventX 제거
eventBus.clear("eventX");
// eventX 재발행. eventX에 대한 이벤트가 제거되어 모든 모듈에서 이벤트를 수신할 수 없다
eventBus.publish<PublishType>("eventX", { msg: "EventX published again!" }, 2);
// 결과
[LOG]: "Module A", {
"msg": "EventX published!"
}, 1
[LOG]: "Module B", {
"msg": "EventX published!"
}, 1
[LOG]: "Module C", {
"msg": "EventX published!"
}, 1
[WRN]: "eventX not found!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment