๐Ÿ‘ฅ 28-B ํŒ€, J238 J188

์ฒดํฌํฌ์ธํŠธ

ํ•™์Šตํ•˜๊ธฐ

  • Publisher-Subscriber ํŒจํ„ด๊ณผ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด

  • ๋™๊ธฐ์™€ ๋น„๋™๊ธฐ ์ž‘์—… ์ฒ˜๋ฆฌ ๋ฐฉ์‹ ๋น„๊ต

  • ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ํ˜ธ์ถœ ๊ณผ์ •

  • ๋™๊ธฐํ™” ๊ณผ์ •

  • ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ๋ฐฉ์‹๊ณผ ์Šค๋ ˆ๋“œ์—์„œ ๋น„๋™๊ธฐ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ๋ฐฉ์‹

  • ํŠน์ • ์Šค๋ ˆ๋“œ์—์„œ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ๋งŒ๋“ค์–ด ๊ฐ ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ์‹

  • ๋น„๋™๊ธฐ ์ž‘์—…์„ ๋™๊ธฐํ™”ํ•ด์„œ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฐฉ์‹

  • ๋น„๋™๊ธฐ ์ž‘์—…์„ ๊ทธ๋ฃน์œผ๋กœ ๋ฌถ์–ด์„œ ๋™๊ธฐํ™”ํ•˜๋Š” ๋ฐฉ์‹

  • ๋…ธ๋“œ ํ™˜๊ฒฝ์—์„œ ์ด๋ฒคํŠธ ๋ฃจํ”„์™€ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ(Event Emmiter) ๋ฐฉ์‹

  • ์—ฌ๋Ÿฌ Thread๋ฅผ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด Pool ํ˜•ํƒœ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์‹

์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„ํ•˜๊ธฐ

  • EvenyManager ํด๋ž˜์Šค ์„ค๊ณ„

  • SharedInstance ํ•จ์ˆ˜

  • Subscriber ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์™€ ํ‘œ

  • Subscriber ํด๋ž˜์Šค

  • Sender ํด๋ž˜์Šค

  • remove ํ•จ์ˆ˜

  • postEvent ํ•จ์ˆ˜

  • stringify ํ•จ์ˆ˜

  • ๋น„๋™๊ธฐ ๊ฐœ์„  โœ… 2024-07-26

    ๊ตฌ์กฐ ์„ค๊ณ„


classDiagram


Subscriber <|-- EventManager
EventManager <|-- sharedInstance
sharedInstance <|-- Publisher


  

class Publisher{
	name: string
	eventmanager = sharedInstance()
	+postEventPub()
	+asyncPostEventPub()
	+delayPostEventPub()
}

class Subscriber{
	name: string
}

class EventManager {

subscribersInfo: string[]

static instance

add()

remove()

postEvent()

stringify()
checkValidity()
addSubscriber()
callEvent()
asyncPostEvent()

}

class Event{

+name: string

+sender: object

+userData: object

}

class sharedInstance{
	return EventManager
}
  


Pub-Sub ํŒจํ„ด

๋ฐœํ–‰-๊ตฌ๋… ํŒจํ„ด์€ Publisher๊ฐ€ Subscriber์˜ ์œ„์น˜๋‚˜ ์กด์žฌ๋ฅผ ์•Œ ํ•„์š” ์—†์ด ๋ธŒ๋กœ์ปค์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ๋˜์ ธ๋†“๊ธฐ๋งŒ ํ•˜๋ฉด ๋˜๋ฉฐ ๋ฐ˜๋Œ€๋กœ Subscriber ์—ญ์‹œ ๋ธŒ๋กœ์ปค์— ํ• ๋‹น๋œ ์ž‘์—…๋งŒ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋‹ค ์ž‘์—…ํ•˜๋ฉด ๋˜๋ฏ€๋กœ ์˜ต์ €๋ฒ„ ํŒจํ„ด์— ๋น„ํ•ด ๊ฒฐํ•ฉ๋„๊ฐ€ ๋” ๋‚ฎ๋‹ค.

๋˜ํ•œ ๋ฐœํ–‰-๊ตฌ๋… ํŒจํ„ด์€ ๋ธŒ๋กœ์ปค๋ผ๋Š” ์ค‘๊ฐ„ ๋งค๊ฐœ์ฒด๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ธŒ๋กœ์ปค์— ์ง์ ‘ ์ ‘๊ทผํ•˜์—ฌ ์ฒ˜๋ฆฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

๊ตฌํ˜„ํ•˜๊ธฐ

EventManager ํด๋ž˜์Šค

EventManager ํด๋ž˜์Šค๋Š” ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์ด์šฉํ•˜์—ฌ ๊ณต์œ ํ•˜๋Š” EventManager๋ฅผ ํ†ตํ•ด Publisher๊ฐ€ EventManager์— ๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ๋กœ๋ฅผ ๋งˆ๋ จํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. SharedInstance๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด new ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ–ˆ์ง€๋งŒ, ์ƒ์„ฑ๋œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ๊ธฐ์กด์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“ค์–ด Publisher์˜ eventManager property์—๋„ ๋„ฃ์–ด์ฃผ์–ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์˜€๋‹ค.

class Publisher {
  constructor(name) {
    this.name = name;
    this.eventManager = sharedInstance();
  }
...
}
class EventManager {
  static instance;
 
  constructor() {
    if (EventManager.instance) {
      return EventManager.instance;
    }
    this.subscriberInfos = []; // ๊ตฌ๋…์ž ๋ชฉ๋ก ์ €์žฅ ๋ฐฐ์—ด
    EventManager.instance = this;
    this.eventEmitter = new EventEmitter();
  }
  ...

์ด๋ ‡๊ฒŒ Publisher๊ฐ€ ์ง์ ‘์ ์œผ๋กœ ๊ณต์œ ํ•˜๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ํ†ตํ•ด Publisher ์ž์ฒด์˜ property์—์„œ EventManager๋กœ ๊ฐˆ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€ ๋‹ค์Œ์— ์ด๋ฒคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ Publisher ์•ˆ์—์„œ ๋งŒ๋“  ๋‹ค์Œ EventMager๋กœ ์ „๋‹ฌํ•ด์ฃผ์–ด ์ƒ์„ฑ๋˜๊ฒŒ๋” ํ•ด์ฃผ๋ฉด์„œ ๋‹ค์ˆ˜์˜ ์ด๋ฒคํŠธ๊ฐ€ ์žˆ๋”๋ผ๋„ ํ•˜๋‚˜์˜ Publisher๋ฅผ ํ†ตํ•ด ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ๊ณ ์•ˆํ–ˆ๋‹ค.

add ํ•จ์ˆ˜

 // subscriber ๋“ฑ๋ก (eventName, sender)
  add(subscriber, eventName, sender, handler) {
    const subscribeData = {
      subscriber: subscriber,
      eventName: eventName,
      sender: sender,
      handler: handler,
    };
    if (
      this.subscriberInfos.some((subInfo) =>
        this.#checkValidity(subInfo, subscribeData)
      )
    ) {
      return;
    }
    this.subscriberInfos.push(subscribeData);
    return;
  }

์ „์ฒด์ ์œผ๋กœ EventManager์—์„œ ์กด์žฌํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋“ค์€ ๋ณต์žกํ•œ ๋กœ์ง์œผ๋กœ ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค. ์œ ํšจ์„ฑ(๊ฐ™์€ ์ด๋ฆ„์˜ ์ด๋ฒคํŠธ ๊ฑธ๋Ÿฌ์ฃผ๊ธฐ)๋งŒ ๊ฒ€์‚ฌํ•ด์ค€ ๋’ค์— subscriberInfos๋ผ๋Š” ๋ฐฐ์—ด์— ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๊ฒŒ๋” ํ•˜๊ณ , ๋‚˜์ค‘์— ํ•ด๋‹น ๋ฐฐ์—ด์— ๋Œ€ํ•ด์„œ๋งŒ ๊ด€๋ฆฌํ•˜๋ฉด์„œ ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

PostEvent ํ•จ์ˆ˜

postEvent(eventName, sender, userInfo) {
    const newEvent = new Event(eventName, sender, userInfo);
    let result;
    this.subscriberInfos.forEach((subscriberInfo) => {
      if (
        !subscriberInfo.eventName ||
        (subscriberInfo.eventName === eventName &&
          subscriberInfo.sender.name === sender.name) ||
        !subscriberInfo.sender
      ) {
        process.stdout.write(`${subscriberInfo.subscriber.name}: `);
        console.log(
          `${subscriberInfo.subscriber.name}: ${eventName} event from ${
            sender.name
          } userData = ${JSON.stringify(userInfo)} `
        );
        result = subscriberInfo.handler(newEvent);
      }
    });
    return result;
  }

postEvent ํ•จ์ˆ˜๋Š” ์ด๋ฏธ ์ถ”๊ฐ€์‹œํ‚จ ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด์„œ ์‹คํ–‰์‹œ์ผœ์ฃผ๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค. ํ•ด๋‹น ๋ฉ”์†Œ๋“œ์—์„œ๋Š” eventName, sender ์ธ์Šคํ„ด์Šค, userInfo ๊ฐ์ฒด๋ฅผ ๋ฐ›๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋ฐ›์€ ์ธ์ˆ˜๋ฅผ ํ† ๋Œ€๋กœ ์ƒˆ๋กœ์šด Event๋ผ๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ณ , ์ด์— ๋Œ€ํ•ด ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜๊ฐ€ ํด๋กœ์ €๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๊ฒŒ๋” ํ•ด์ฃผ์—ˆ๋‹ค.

์ด ๋•Œ, ๋งจ ์ฒ˜์Œ์— eventName์ด "" ๋นˆ ๋ฌธ์ž์—ด๋กœ ๋˜์–ด ์žˆ์œผ๋ฉด ๋ชจ๋“  ์ด๋ฒคํŠธ๋ฅผ ์‹คํ–‰์‹œ์ผœ์ฃผ์–ด์•ผ ํ•˜๊ณ , Publisher์˜ ์ด๋ฆ„์ด undefined๋ผ๋ฉด ๋ชจ๋“  ์ด๋ฒคํŠธ๋ฅผ ์‹คํ–‰์‹œ์ผœ ์ฃผ์–ด์•ผ ํ–ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” ์ด๋Ÿฌํ•œ ๋ฐฐ์—ด์„ ๋งŒ๋“ค๊ธฐ ์ „์— ๋“ค์–ด์˜ค๋Š” ๊ฐ’์— ๋Œ€ํ•ด ๊ฒ€์‚ฌ๋ฅผ ํ•˜๊ณ , ๋นˆ ๋ฌธ์ž์—ด์˜ ๊ฒฝ์šฐ์™€ undefined๋œ Publisher์˜ ์ด๋ฆ„์— ๋Œ€ํ•ด์„œ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ๊ณ  ์ƒํ™ฉ์— ๋งž๊ฒŒ ๋ชจ๋“  ์ด๋ฒคํŠธ๋“ค์„ ๋งŒ๋“ค์–ด๋‚ผ๊นŒ ์ƒ๊ฐ์„ ํ–ˆ์—ˆ๋Š”๋ฐ, ์ด๋ ‡๊ฒŒ ๋…ผ๋ฆฌ์—ฐ์‚ฐ์ž์™€ ๊ณ ์ฐจํ•จ์ˆ˜์˜ ์ด์šฉ์„ ํ†ตํ•ด์„œ ์ด๋ฒคํŠธ๋ฅผ ์‹คํ–‰์‹œ์ผœ์ฃผ๋Š” ํŽธ์ด ๋ณด๋‹ค ๋ฉ”๋ชจ๋ฆฌ ์ ˆ์•ฝ์ด ๋˜์ง€ ์•Š์•˜๋‚˜ ์ƒ๊ฐํ•œ๋‹ค.

remove ํ•จ์ˆ˜

  remove(subscriber) {
    this.subscriberInfos = this.subscriberInfos.filter(
      (subscriberInfo) => subscriberInfo.subscriber !== subscriber
    );
  }

removeํ•จ์ˆ˜๋Š” filter ๊ณ ์ฐจํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ๋น„๊ตํ•˜๋ฉด์„œ ๊ฑธ๋Ÿฌ์ค„ ์ˆ˜ ์žˆ์—ˆ๋‹ค

stringify ํ•จ์ˆ˜

์ฒ˜์Œ์—๋Š” stringify๊ฐ€ ์กฐ๊ฑด์„ ์•Œ๋ ค์ฃผ๋Š” ํ•จ์ˆ˜๋ผ๊ธธ๋ž˜ ๋ฌด์Šจ ๋ง์ธ๊ฐ€ ํ–ˆ๋‹ค. ์–ด์ฐจํ”ผ ์ด๋ฒคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์กฐ๊ฑด์˜ ๊ฒฝ์šฐ๋Š” ์œ„์—์„œ ์ด๋ฒคํŠธ ์‹คํ–‰ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด์„œ ๊ฑธ๋Ÿฌ์ฃผ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ค subscriber์— ์–ด๋–ค event๋“ค์ด ๋“ค์–ด๊ฐ€ ์žˆ๋Š”์ง€๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ํ•จ์ˆ˜์ •๋„๋ผ๊ณ  ํ•ด์„ํ•ด์‹ฟ.

  stringify() {
    this.subscriberInfos.forEach((subscriberInfo) => {
      console.log(
        `${subscriberInfo.subscriber.name} : event name = "${subscriberInfo.eventName}", sender = ${subscriberInfo.sender.name}`
      );
    });
  }

addSubscriber , callEvent ํ•จ์ˆ˜

addSubscriber(subscriber, eventName, sender, handler) {
    const subscribeData = {
      subscriber: subscriber,
      eventName: eventName,
      sender: sender,
      handler: handler,
    };
    if (
      this.subscriberInfos.some((subInfo) =>
        this.#checkValidity(subInfo, subscribeData)
      )
    ) {
      return;
    }
    this.subscriberInfos.push(subscribeData);
    this.eventEmitter.on(eventName, (data) =>
      this.postEvent(eventName, sender, data)
    );
    return;
  }
 
  callEvent(eventName, data) {
    const result = this.eventEmitter.emit(eventName, data);
    if (!result) return { data: null, completed: false };
    return { data: result, completed: true };
  }

addSubscriber ํ•จ์ˆ˜๋Š” ์กฐ๊ธˆ ๋” ์‚ฌ์šฉ์„ฑ์ด ์ข‹๋„๋ก ๋งŒ๋“ค์–ด์ง„ ํ•จ์ˆ˜์ด๋‹ค. ๊ธฐ์กด add ํ•จ์ˆ˜์˜ ๋ฐœ์ „ํ˜•์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค. ๊ธฐ์กด์˜ add์™€ ๋งˆ์ง€๋ง‰๊นŒ์ง€ ๊ฑฐ์˜ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ์ง€๋…”์ง€๋งŒ, ํฐ ์ฐจ์ด์ ์€ eventEmmiter์˜ ์œ ๋ฌด์ด๋‹ค. eventEmmiter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ๋ณด๋‹ค ๊ฐ„๊ฒฐํ•˜๊ฒŒ callEvent(์ด๋ฒคํŠธ ์ด๋ฆ„, ๋ฐ์ดํ„ฐ)์˜ ํ˜•ํƒœ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์–ด ๋‹ค๋ฅธ ์ •๋ณด๋“ค์„ ๊ตณ์ด ๊ธฐ์žฌํ•  ๋ถˆํŽธํ•จ์„ ๊ฐ์†Œ์‹œ์ผฐ๋‹ค.

AsyncPostEvent ํ•จ์ˆ˜

asyncPostEvent(eventName, sender, userInfo) {
    return new Promise((resolve, reject) => {
      const result = this.postEvent(eventName, sender, userInfo);
      console.log(result);
      if (!result) reject({ completed: false });
      resolve(result);
    });
  }

ํ•ด๋‹น ํ•จ์ˆ˜๋Š” postEvent์™€ ๊ฐ™์€ ์—ญํ• ์„ ํ•˜์ง€๋งŒ ๋น„๋™๊ธฐ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„๋œ ํ•จ์ˆ˜์ด๋‹ค. ์ฐจ์ด์ ์€ Promise๋ฅผ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” .then์ด๋‚˜ async/await ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด ๋™๊ธฐ ๋ฐฉ์‹์œผ๋กœ ๋ฐ”๊ฟ”์ค€ ํ›„์— ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

delayPostEvent ํ•จ์ˆ˜

delayPostEvent(eventName, sender, userInfo, timeout) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(this.postEvent(eventName, sender, userInfo));
      }, timeout);
    });
  }
}

delayPostEvent๋Š” ๋น„๋™๊ธฐ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” postEvent ํ•จ์ˆ˜ ๋ฒ„์ „์— ์‹œ๊ฐ„์ง€์—ฐ๊นŒ์ง€ ์ถ”๊ฐ€ํ•œ ๋ฒ„์ „์ด๋‹ค. setTimeout์„ ์‚ฌ์šฉํ•ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ํ•ด๋‹นํ•˜๋Š” ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๊ฐ’์„ resolve ์‹œ์ผœ์ฃผ์—ˆ๋‹ค.

Subscriber ํด๋ž˜์Šค

class Subscriber {
  constructor(name) {
    this.name = name;
  }
}
 
module.exports = { Subscriber };
 

ํœ‘~ ๊ตณ์ด ์ธ์Šคํ„ด์Šคํ™”์‹œํ‚ค์ง€ ๋ง๊ณ  ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ๋งŒ๋“ค์–ด๋„ ์ข‹์•˜์„๋“ฏโ€ฆ?

Publisher ํด๋ž˜์Šค

const { EventManager, sharedInstance } = require("./eventManager");
 
class Publisher {
  constructor(name) {
    this.name = name;
    this.eventManager = sharedInstance();
  }
 
  postEventPub(eventName, userInfo) {
    return this.eventManager.postEvent(eventName, this, userInfo);
  }
 
  asyncPostEventPub(eventName, userInfo) {
    return this.eventManager.asyncPostEvent(eventName, this, userInfo);
  }
 
  delayPostEventPub(eventName, userInfo) {
    return this.eventManager.delayPostEvent(eventName, this, userInfo);
  }
}
 
module.exports = { Publisher };
 

์–œ ๊ทธ๋‚˜๋งˆ ์žˆ๋Š” ํŽธ์ด๋‹ค. postEventํ•จ์ˆ˜๋“ค์— ๋Œ€ํ•ด์„œ ๋จผ์ € Publisher์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์‹คํ–‰ํ•˜๊ณ  eventManager์— ์ง„์ž…ํ•˜์—ฌ ํ•ด๋‹นํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์„ค๊ณ„ํ•˜์˜€๋‹ค.

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

jest.setTimeout(30000);
const { EventManager } = require("./eventManager");
const { Publisher } = require("./publisher");
const { Subscriber } = require("./subscriber");
 
const eventManager = new EventManager();
const subscriber0 = new Subscriber("testSub0");
const publisher0 = new Publisher("testPub0");
 
describe("ํ…Œ์ŠคํŠธ", () => {
  test("eventManager ๋™์ผ์„ฑ ํ…Œ์ŠคํŠธ", () => {
    const eventManagerA = new EventManager();
    const eventManagerB = new EventManager();
    expect(eventManagerA).toEqual(eventManagerB);
  });
 
  test("Subscriber ๋“ฑ๋ก ํ…Œ์ŠคํŠธ", () => {
    eventManager.add(subscriber0, "test", publisher0, (newEvent) => {
      return "success";
    });
    expect(eventManager.subscriberInfos.length).toBe(1);
  });
 
  test("Subscriber ์ค‘๋ณต ๋“ฑ๋ก ํ…Œ์ŠคํŠธ", () => {
    eventManager.add(subscriber0, "test", publisher0, () => {
      return "success";
    });
    expect(eventManager.subscriberInfos.length).toBe(1);
  });
 
  test("postEvent ๋™์ž‘ ํ…Œ์ŠคํŠธ", () => {
    expect(publisher0.postEventPub("test", { content: "content" })).toBe(
      "success"
    );
  });
 
  test("remove ๋™์ž‘ ํ…Œ์ŠคํŠธ", () => {
    eventManager.remove(subscriber0);
    expect(eventManager.subscriberInfos.length).toBe(0);
  });
 
  test("EventEmmiter ํ…Œ์ŠคํŠธ", () => {
    eventEmitter.emit("addSub", "testSub0", "event", "testPub0", () => {
      console.log("test");
    });
  });
 
  test("addSubscriber ํ…Œ์ŠคํŠธ", () => {
    eventManager.addSubscriber(subscriber0, "emmiterTest", publisher0, () => {
      console.log("์ด๋ฒคํŠธ ๋“ฑ๋ก ํ›„ ์‹คํ–‰");
    });
    expect(eventManager.callEvent("emmiterTest", { data: "wwww" }).data).toBe(
      true
    );
  });
 
  test("asyncPostEvent ํ…Œ์ŠคํŠธ", async () => {
    eventManager.add(subscriber0, "asyncPostEvent test", publisher0, () => {
      return "asyncPostEvent Test";
    });
    const result = await eventManager.asyncPostEvent(
      "asyncPostEvent test",
      publisher0,
      {
        data: "async test",
      }
    );
    expect(result).toBe("asyncPostEvent Test");
  });
 
  test("delayPostEvent ํ…Œ์ŠคํŠธ", async () => {
    eventManager.add(subscriber0, "delayPostEvent test", publisher0, () => {
      return "delayPostEvent Test";
    });
    const result = await eventManager.delayPostEvent(
      "delayPostEvent test",
      publisher0,
      {
        data: "delay test",
      },
      3000
    );
    console.log(result);
    expect(result).toBe("delayPostEvent Test");
  });
 
  test("๋น„๋™๊ธฐ ๋™์ž‘ ์‹œ๋‚˜๋ฆฌ์˜ค ํ…Œ์ŠคํŠธ1", () => {
    const subscriberA = new Subscriber("subscriberA");
    const albumModel = new Publisher("albumModel");
    eventManager.addSubscriber(
      subscriberA,
      "ModelDataChanged",
      albumModel,
      (obj) => {
        return obj.eventName;
      }
    );
    const result = eventManager.callEvent("ModelDataChanged", {
      data: "ModelDataChanged Event",
    });
    expect(result.data).toBe(true);
  });
 
  const testSub = new Subscriber("testSub");
 
  test("๋น„๋™๊ธฐ ๋™์ž‘ ์‹œ๋‚˜๋ฆฌ์˜ค ํ…Œ์ŠคํŠธ2(๋™๊ธฐ)", () => {
    console.log("222");
    const albumTableView = new Publisher("albumTableView");
    eventManager.add(testSub, "syncEvent", albumTableView, (obj) => {
      return obj.eventName;
    });
 
    expect(
      eventManager.postEvent("syncEvent", albumTableView, {
        user: "user",
      })
    ).toBe("syncEvent");
  });
 
  const albumTableViewController = new Publisher("albumTableViewController");
 
  test("๋น„๋™๊ธฐ ๋™์ž‘ ์‹œ๋‚˜๋ฆฌ์˜ค ํ…Œ์ŠคํŠธ 3(๋น„๋™๊ธฐ)", async () => {
    eventManager.add(testSub, "asyncEvent", albumTableViewController, (obj) => {
      return obj.eventName;
    });
    expect(
      await eventManager.asyncPostEvent(
        "asyncEvent",
        albumTableViewController,
        {
          user: "user",
        }
      )
    ).toBe("asyncEvent");
  });
 
  test("๋น„๋™๊ธฐ ๋™์ž‘ ์‹œ๋‚˜๋ฆฌ์˜ค ํ…Œ์ŠคํŠธ 4(์ง€์—ฐ ๋น„๋™๊ธฐ)", async () => {
    console.log("444");
    const dummySub = new Subscriber("dummySub");
    const dummyPub = new Publisher("dummyPub");
    eventManager.add(dummySub, "delayPostEvent", dummyPub, (obj) => {
      return obj.eventName;
    });
    const result = await eventManager.delayPostEvent(
      "delayPostEvent",
      dummyPub,
      {
        data: "delayPostEvent",
      },
      10000
    );
    expect(result).toBe("delayPostEvent");
  });
});
 
>์˜ค๋Š˜์˜ ๊ฟ€ํŒ Jest๋Š” ๊ธฐ๋ณธ ์ตœ๋Œ€ ์ง€์—ฐ ์‹œ๊ฐ„์ด 5์ดˆ๊นŒ์ง€๋กœ ์„ค์ •๋˜์–ด ์žˆ๋‹ค. ์ด๋ฅผ ๋Š˜๋ฆฌ๊ณ  ์‹ถ์œผ๋ฉด ์ฝ”๋“œ์˜ ์ตœ์ƒ๋‹จ์— jest.timeOut(์‹œ๊ฐ„) ์“ฐ๋ฉด ๋œ๋‹ค ์•ผํ˜ธ~

ํ›„๊ธฐ

์—ญ์‹œ ๋ˆ„๊ตฐ๊ฐ€์™€ ํ•จ๊ป˜ ํ•œ๋‹ค๋Š”๊ฑด ์–ด๋ ต์ง€๋งŒ ๋ง‰์ƒ ํ•จ๊ป˜ ๋งŒ๋“  ๊ฒฐ๊ณผ๋ฌผ์„ ๋ณด๋‹ˆ ๋„ˆ๋ฌด ๋ฟŒ๋“ฏํ•˜๋‹ค. ์—ญ์‹œ 1+1=2์ด๋“ฏ์ด ๋‘๋‡Œ๊ฐ€ ๋ชจ์ด๋ฉด ๋” ๋นจ๋ฆฌ, ์ข‹์€ ๊ฒฐ๊ณผ๋ฌผ์„ ๋งŒ๋“œ๋‚˜๋ณด๋‹ค ์‚ด๋ฉด์„œ ๋””์ž์ธํŒจํ„ด์— ๋Œ€ํ•ด์„œ ๋ง๋งŒ ๋“ค์—ˆ์ง€, ์ง์ ‘ ๊ณต๋ถ€ํ•˜๊ณ  ์จ๋ณผ ์ค„์€ ๋ชฐ๋ž๋Š”๋ฐ ๋‚ด๊ฐ€ ๋ฒŒ์จ ์ด๋Ÿฐ๊ฑธ ๊ณต๋ถ€ํ•  ๋•Œ๋ผ๋‹ˆ..