게시 구독 모드 및 EventEmitter 클래스 구현

전단 개발 에 서 는 게시 구독 모드 에 자주 사용 되 며 게시 구독 모드 도 관찰자 모드 라 고 부른다.가장 흔히 볼 수 있 는 게시 구독 모드 는 DOM 바 인 딩 이벤트 입 니 다. 단 추 를 누 르 거나 마 우 스 를 누 르 면 이벤트 감청 함 수 를 터치 한 다음 텍스트 상 자 를 팝 업 하거나 요소 스타일 을 바 꿉 니 다.
div.addEventListener("click", () => {
    alert("Hello!");
});
div 요 소 는 구독 자 에 해당 합 니 다. 그 는 브 라 우 저 (게시 자) 에 게 click 이 벤트 를 구독 하 라 고 알려 줍 니 다. 이 이 벤트 는 알림 상자 가 팝 업 됩 니 다.사용자 가 div 요 소 를 클릭 하면 브 라 우 저 는 이 메 시 지 를 발표 하여 사용자 에 게 알려 줍 니 다.Node.js 에서 도 게시 구독 모델 을 대량으로 응 용 했 는데 이것 은 Node.js 플랫폼 을 구성 하 는 핵심 중 하나 이다.예 를 들 어 응답 post 요청 에 응 할 때 데 이 터 를 받 으 려 면 요청 대상 에 게 귀속 data 사건 을 전송 하 는 데 사용 할 수 있 습 니 다. 데이터 수신 이 끝나 면 end 사건 이 발생 합 니 다. 우 리 는 그 중에서 완전한 요청 데 이 터 를 얻 을 수 있 습 니 다.
const http = require("http");

const httpServer = http.createServer((req, res) => {
    let { url } = req;
    let method = req.method.toLocaleLowerCase();

    if(method === "post"){
        if(url === "/data"){
            let str = "";
            //    data   ,          
            req.on('data', (chunk) => {
                str += chunk;
            });
            //            end   
            req.on('end', () => {
                console.log("str === ", str);

                res.write("OK!");
                res.end();
            });
        }
    }
});
httpServer.listen(8888, () => {
    console.log("Server is running: http://localhost:8888");
});

전단 은 게시 구독 모드 를 이용 하여 요소 바 인 딩 이벤트 Node.js 에서 게시 구독 모드 를 이용 하여 요청 데 이 터 를 처리 할 수 있 습 니 다.이 게시 구독 모드 는 모두 내 장 된 것 으로 Node.js 중 하나 events 모듈 이 있 습 니 다. 이 모듈 에는 하나 EventEmitter 클래스 가 있 습 니 다. EventEmitter 하나 이상 의 함 수 를 감청 기로 등록 할 수 있 고 이벤트 가 발생 하면 해당 함수 가 호출 됩 니 다.Node.js 중의 많은 모듈 이 이런 유형 을 계승 하여 사건 감청 능력 을 가지 게 되 었 다.EventEmitter 내부 에서 하나의 사건 감청 함수 집합 을 유지 하고 내부 의 방법 emit 이 호출 되면 해당 하 는 감청 함 수 를 촉발 합 니 다.예 를 들 면:
const EventEmitter = require("events").EventEmitter;

const event = new EventEmitter();

var c = () => console.log("aaa -- second");
//     
event.on("aaa", () => console.log("aaa -- first"))
    .once("aaa", () => console.log("aaa -- once"))
    .on("aaa", c, true)

//     
event.emit("aaa");
console.log("
"
); event.emit("aaa"); // event.removeEventListener("aaa", c); console.log("
"
); event.emit("aaa");

구독 이 벤트 는 체인 으로 호출 할 수 있 습 니 다. 위의 코드 에 세 개의 aaa 이벤트 가 등록 되 어 있 는데 그 중 하 나 는 once 이 트리거 를 한 번 표시 합 니 다.이벤트 함수 이름 은 모두 aaa 이지 만 바 인 딩 된 함수 가 다 르 기 때문에 호출 emit 하면 여러 함수 가 실 행 됩 니 다.removeEventListener 이벤트 의 c 함 수 를 제거 할 수 있 습 니 다.
하나의 이벤트 가 여러 개의 감청 함 수 를 연결 할 수 있 도록 하려 면 쉽게 등 록 된 함 수 를 배열 에 저장 하면 됩 니 다. 이벤트 가 실 행 될 때 배열 의 함 수 를 모두 실행 합 니 다.다음은 하나 aaa 류 를 실현 하 겠 습 니 다.
EventEmitter
간단하게 실현 해 봐.EventEmitter 클래스 는 감청 함 수 를 저장 하 는 데이터 구조 가 필요 합 니 다. 대상 을 사용 하면 됩 니 다. 대상 의 키 는 이벤트 이름 이 고 값 은 배열 로 감청 함 수 를 저장 합 니 다.
class EventEmitter{
    event: {    //    on        
        [eventName: string]: Function[];
    }
    onceEvent: {    //    once        
        [eventName: string]: Function[];
    }

    constructor(){
        //    
        this.event = {};
        this.onceEvent = {};
    }
}

on 과 once 함수
이벤트 감청 함 수 를 연결 하고 EventEmitter 인 스 턴 스 를 되 돌려 줍 니 다.once 함수 와 on 함수 가 기본적으로 같 으 면 통용 되 는 EventEmitter 함 수 를 실현 할 수 있 습 니 다.
_bind(type: string, eventName: string, listener: Function, flag = false): EventEmitter{
    const event = type === "on" ? this.event : this.onceEvent;
    const fnAry = event[eventName];
    if(!fnAry){
        event[eventName] = [listener];
    }else{
        //            ,   
        if(!fnAry.includes(listener)){
            if(typeof listener === "function")
                flag ? event[eventName].unshift(listener)
                    : event[eventName].push(listener);
        }
    }
    return this;
}

on(eventName: string, listener: Function, flag = false): EventEmitter{
    return this._bind('on', eventName, listener, flag);
}
//         ,            
once(eventName: string, listener: Function, flag = false): EventEmitter{
    return this._bind('once', eventName, listener, flag);
}
bindon 함수 모두 하나의 once 인 자 를 받 아들 일 수 있 습 니 다. 기본 값 은 false 입 니 다.flag 일 때 true 함수 가 배열 의 맨 앞 에 추 가 됩 니 다 (unshift 작업). 이 벤트 를 촉발 할 때 우선 호출 됩 니 다.listeneraddEventListener 함수 와 마찬가지 로 별칭 일 뿐이다.
addEventListener(eventName: string, listener: Function, flag = false): EventEmitter{
    return this.on(eventName, listener, flag);
}
on 클래스 에 서 는 EventEmitterprependListener 함 수 를 제공 합 니 다. 이 두 함 수 는 각각 prependOnceListeneron 두 가지 바 인 딩 방식 에 대응 합 니 다.
//   flag       true
prependListener(eventName: string, listener: Function): EventEmitter{
    return this.on(eventName, listener, true);
}
prependOnceListener(eventName: string, listener: Function): EventEmitter{
    return this.once(eventName, listener, true);
}

emit
이 벤트 를 촉발 하여 true 로 돌아 가 는 데 성공 하 였 습 니 다. 그렇지 않 으 면 false 로 돌아 갑 니 다.
_perform(fnAry: Function[], ...args: any[]){
    fnAry.forEach(fn => {
        fn.apply(this, args);
    });
}
emit(eventName: string, ...args: any[]): boolean{
    //     on     ,    once     
    const onEventFn = this.event[eventName];
    const onceEventFn = this.onceEvent[eventName];
    let flag = false;
    if(onEventFn){
        flag = true;
        this.perform(onEventFn, ...args);
    }
    if(onceEventFn){
        flag = true;
        this.perform(onceEventFn, ...args);
        //      ,          
        delete this.onceEvent[eventName];
    }
    return flag;
}

removeEventListener
코드 는 다음 과 같 습 니 다:
removeEventListener(eventName: string, listener: Function): EventEmitter{
    let onEventFn = this.event[eventName];
    let onceEventFn = this.onceEvent[eventName];
    if(onEventFn){
        //   
        this.event[eventName] = onEventFn.filter(fn => && fn !== listener);
    }
    if(onceEventFn){
        this.onceEvent[eventName] = onceEventFn.filter(fn => && fn !== listener);
    }
    return this;
}
once 방법 외 에 도 하나의 removeEventListener 를 실현 하여 제거 removeAllListener 에 대응 하 는 모든 감청 함 수 를 표시 할 수 있다.
removeAllListener(eventName: string): EventEmitter{
    delete this.event[eventName];
    delete this.onceEvent[eventName];
    return this;
}

기본 적 인 게시 구독 모드 가 실현 되 었 다.
전단 - 사용자 정의 이벤트
말 이 끝나 면 eventName 전단 의 사용자 정의 사건 에 대해 이야기 합 니 다.
어떤 요소 에 대해 자신 이 정의 하 는 이벤트 형식 을 설정 하려 면 어떻게 합 니까?예 를 들 면:
div.addEventListener("myEvent", (e) => {
    // ...
});

CustomEvent
아래 와 같이 사용:
//     event   
var event = new CustomEvent("color", {
    detail: {
        color: 'red'
    },
    bubbles: false,
    cancelable: true,
});

const div = document.getElementById("main");
//     
div.addEventListener("color", function(e){
    console.log(e);
});

//     
div.dispatchEvent(event);
EventEmitter 구조 함수 가 두 개의 인 자 를 받 습 니 다. 첫 번 째 는 이벤트 이름 이 고 두 번 째 는 설정 매개 변수 입 니 다. 설정 항목 은 다음 과 같 습 니 다.
  • CustomEvent 하나의 불 값 은 이 사건 이 거품 이 일어 날 지 여 부 를 나타 낸다.
  • bubbles 하나의 불 값 은 이 사건 이 취 소 될 수 있 는 지 를 나타 낸다.
  • cancelable 사건 이 초기 화 될 때 전달 하 는 데이터;
  • detail 방법 으로 사건 을 촉발 하 다.dom.dispatchEvent 설정 항목 이 bubbles 일 때 이 사건 이 거품 이 생 길 수 있 음 을 나타 낸다.
    var event = new CustomEvent("color", {
        detail: {
            color: 'red'
        },
        bubbles: true,
        cancelable: true,
    });
    //   document     
    document.addEventListener("color", function(e){
        console.log(e);
    });
    
    //   div     
    div.dispatchEvent(event);
    

    위의 코드 는 true 사건 이 거품 을 일 으 킬 수 있 기 때문에 div 요소 도 촉발 할 수 있 습 니 다.
    Event color 류 는 Event 류 와 비슷 하 다.용법 은 다음 과 같다.
    const div = document.getElementById("main");
    var event = new Event('color', {
        "bubbles": true,
        "cancelable": true,
    });
    
    document.addEventListener("color", (e) => console.log(e));
    div.dispatchEvent(event);
    document.dispatchEvent(event);
    
    CustomEvent 에 비해 CustomEvent 구조 함수 의 두 번 째 매개 변수 인 설정 항목 에서 초기 화 데 이 터 를 전달 할 수 없 을 것 같 습 니 다 Event.
    전단 의 detail 함수 도 요소 에 일회 성 이 벤트 를 등록 할 수 있 고 세 번 째 매개 변수 에 하나의 대상 을 입력 하여 addEventListeneronce 로 설정 하면 됩 니 다.
    div.addEventListener("click", () => {
        // ...
    }, {
        once: true,      //      
        capture: false, //          
    });
    

    좋은 웹페이지 즐겨찾기