본문 바로가기
WEB/JS

(js)Promise만들기(3) - CustomEvent, EventTarget

by jackWillow 2024. 1. 28.

←(js)Promise만들기(2) - 구상

 

이벤트 기반으로 프로미스를 만드려고 했는데, IE에 CustomEvent와 EventTarget이 없어서 직접 만들어야 했습니다.
다행히도 둘 다 MDN에 polyfill이 있었습니다. (그런데 지금은 없어요.)

CustomEvent

// myCustomEvent.js

/**
 * 커스텀 이벤트 생성자
 * @param {string} event 
 * @param {object} params 
 * @returns {object} customEvent
 */
var MyCustomEvent = (function setCustomEventConstructor() {
  /**
   * window.CustomEvent의 constructor를 지원하지 않을 때(IE) CustomEvent() 폴리필을 구현.
   * MDN CustomEvent() Polyfill 참고.
   * https://developer.mozilla.org/ko/docs/Web/API/CustomEvent/CustomEvent
   */
  if (typeof window.CustomEvent !== "function") {
      function MyCustomEvent ( event, params ) {
          params = params || { bubbles: false, cancelable: false, detail: undefined };
          var evt = document.createEvent( 'CustomEvent' );
          evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
          return evt;
      }
      MyCustomEvent.prototype = window.Event.prototype;
      
      return MyCustomEvent
  }

  return  window.CustomEvent
})()

 

기본적으로 둘 다 실제 window.CustomEvent나 window.EventTarget이 있으면 그것을 사용하도록 만들었습니다.

간단히 설명하자면,

MyCustomEvent 생성자를 만들고, 그 안에서 createEvent로 이벤트를 만든 후 initCustomEvent로 CustomEvent로 초기화하고 반환합니다.

그리고 MyCustomeEvent의 프로토타입을 Event 프로토타입으로 바꿔줍니다.

 

현재는 createEvent 대신에 CustomeEvent를 사용하라고 경고하고 있고, initCustomEvent는 아예 완전히 Deprecated 되었습니다.


EventTarget

// customEventTarget.js

/**
 * 이벤트 타겟 생성자
 * @returns {object} eventTarget
 */
var CustomEventTarget = (function setEventTargetConstructor() {
  /**
   * window.EventTarget의 constructor를 지원하지 않을 때(IE) EventTarget 폴리필을 구현.
   * MDN EventTarget 구현 예제 참고.
   * https://developer.mozilla.org/ko/docs/Web/API/EventTarget
   */
  if(typeof window.EventTarget !== "function") {
      var CustomEventTarget = function() {
          this.listeners = {};
      };
      
      CustomEventTarget.prototype.listeners = null;
      CustomEventTarget.prototype.addEventListener = function(type, callback) {
          if (!(type in this.listeners)) {
              this.listeners[type] = [];
          }
          this.listeners[type].push(callback);
      };
      
      CustomEventTarget.prototype.removeEventListener = function(type, callback) {
          if (!(type in this.listeners)) {
              return;
          }
          var stack = this.listeners[type];
          for (var i = 0, l = stack.length; i < l; i++) {
              if (stack[i] === callback){
              stack.splice(i, 1);
              return;
              }
          }
      };
      
      CustomEventTarget.prototype.dispatchEvent = function(event) {
          if (!(event.type in this.listeners)) {
              return true;
          }
          var stack = this.listeners[event.type].slice();
          
          for (var i = 0, l = stack.length; i < l; i++) {
              stack[i].call(this, event);
          }
          return !event.defaultPrevented;
      };

      return CustomEventTarget
  }

  return  window.EventTarget
})()

 

CustomEventTarget역시 생성자를 만들면서 그안에 이벤트를 저장할 listeners객체를 만들어 둡니다.

CustomEventTarget의 메소드로 addEventListener, removeEventListener, dispatchEvent를 만듭니다.

여기서 이벤트를 listeners객체에 이벤트 이름을 key값으로한 배열에 저장 및 삭제하는 식으로 관리합니다.

그래서 같은 프로미스에 .then이 여러번 호출되더라도 문제없이 동작할 수 있습니다.

 

→(js)Promise만들기(4) - constructor, resolve, reject

 

출처: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent

 

CustomEvent: CustomEvent() constructor - Web APIs | MDN

The CustomEvent() constructor creates a new CustomEvent object.

developer.mozilla.org

출처: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget

 

EventTarget - Web APIs | MDN

The EventTarget interface is implemented by objects that can receive events and may have listeners for them. In other words, any target of events implements the three methods associated with this interface.

developer.mozilla.org

 

반응형