Vue Socket.io 소스 코드 해독

9986 단어 VueSocket.io
배경
올해 12 월 재 구성 을 시작 한 프로젝트 가 socket 과 관련 이 있 습 니 다.하지만 socket 은 이전 개발 자 에 의 해 봉 인 된 가방 을 사용 합 니 다.따라서 이 재 구성 기 회 를 틈 타 vue-socket.io 를 도입 하고 백 엔 드 는 socket.io 를 사용 합 니 다.저도 궁금 해서 vue-socket.io 의 소스 코드 를 봤 어 요.
시작 하 다
파일 구조

우 리 는 주로 src 아래 의 세 개의 파일 을 보 았 는데,이 라 이브 러 리 는 관찰자 모드 를 사 용 했 음 을 알 수 있다.
Main.js

//       observe  ,         Observer.js  
let observer = new Observer(connection, store)

//  socket    vue    ,     
//  vue      this.$socket.emit('xxx', {})
Vue.prototype.$socket = observer.Socket;

import store from './yourstore'
Vue.use(VueSocketio, socketio('http://socketserver.com:1923'), store);
우리 가 이 라 이브 러 리 를 사용 하려 면 보통 이렇게 쓰 는 코드(위의 그림 2)입 니 다.위의 그림 1 의 connection 과 store 는 각각 그림 2 의 두 개의 매개 변수 이다.socket 으로 연 결 된 url 과 vuex 의 store 라 는 뜻 입 니 다.그림 하 나 는 이 두 인 자 를 Observer 에 전달 하고 observer 대상 을 새로 만 든 다음 observer 대상 의 socket 속성 을 Vue 프로 토 타 입 에 마 운 트 하 는 것 이다.그러면 우 리 는 Vue 의 인 스 턴 스 에서 this.$sockets.emit('xxx',{})를 직접 할 수 있 습 니 다.

// 👇   vue            
Vue.mixin({
  created(){
    let sockets = this.$options['sockets']

    this.$options.sockets = new Proxy({}, {
      set: (target, key, value) => {
        Emitter.addListener(key, value, this)
        target[key] = value
        return true;
      },
      deleteProperty: (target, key) => {
        Emitter.removeListener(key, this.$options.sockets[key], this)
        delete target.key;
        return true
      }
    })

    if(sockets){
      Object.keys(sockets).forEach((key) => {
        this.$options.sockets[key] = sockets[key];
      });
    }
  },
  /**
   *  beforeDestroy   ,  created     socket  ,      
   * delete this.$option.sockets      ,           
   */
  beforeDestroy(){
    let sockets = this.$options['sockets']

    if(sockets){
      Object.keys(sockets).forEach((key) => {
        delete this.$options.sockets[key]
      });
    }
  }
다음은 Vue 인 스 턴 스 의 수명 주기 에 조작 을 하 는 것 입 니 다.만 들 때 인 스 턴 스 의$options.sockets 값 을 캐 시 한 다음$options.sockets 를 proxy 대상 으로 가리 키 면 이 proxy 대상 은 외부 에서 할당 하고 속성 을 삭제 하 는 것 을 차단 합 니 다.여기 서 값 을 할당 할 때 키 는 socket 이벤트 이 고 값 은 반전 함수 입 니 다.값 을 할당 할 때 이 사건 을 감청 한 후 리 셋 함 수 를 이 socket 이벤트 에 대응 하 는 리 셋 배열 에 넣 습 니 다.삭제 할 때 이 사건 을 감청 하 는 것 을 취소 하 는 것 입 니 다.할당 할 때 리 셋 배열 의 리 셋 함 수 를 누 르 고 삭제 하 는 것 은 제 가 감청 하지 않 겠 다 는 뜻 입 니 다.이렇게 쓰 는 것 은 사실 vue 의 응답 식 과 같은 이치 이다.따라서,우 리 는 감청 socket 사건 을 동적 으로 추가 하고 제거 할 수 있 습 니 다.예 를 들 어 this.$option.sockets.xxx=()=>()와 delete this.$option.sockets.xxx.마지막 으로 캐 시 값 을 순서대로 할당 하면 다음 그림 의 작성 방법 과 같이 이 벤트 를 감청 하고 리 셋 함 수 를 실행 합 니 다.

var vm = new Vue({
 sockets:{
  connect: function(){
   console.log('socket connected')
  },
  customEmit: function(val){
   console.log('this method was fired by the socket server. eg: io.emit("customEmit", data)')
  }
 },
 methods: {
  clickButton: function(val){
    // $socket is socket.io-client instance
    this.$socket.emit('emit_method', val);
  }
 }
})
Emitter.js
Emitter.js 는 주로 Emitter 대상 을 썼 는데 이 대상 은 세 가지 방법 을 제공 했다.
addListener

addListener(label, callback, vm) {
  //              
  if(typeof callback == 'function'){
    //           ,  map            
    //     ,               ,            
    //   ,             
    this.listeners.has(label) || this.listeners.set(label, []);
    this.listeners.get(label).push({callback: callback, vm: vm});

    return true
  }

  return false
}
사실은 매우 일반적인 일이 다.구독 자 모델 이나 관찰자 모델 코드 를 발표 하 는 학생 들 은 이 코드 의 뜻 을 잘 알 고 있다.Emiiter 는 이벤트 와 대응 하 는 리 셋 이벤트 그룹 을 맵 으로 저장 합 니 다.이 코드 는 맵 에 이 이벤트 가 저장 되 어 있 는 지 여 부 를 먼저 판단 합 니 다.없 으 면 이 이벤트 에 대응 하 는 값 을 빈 배열 로 초기 화 한 다음 에 현재 의 반전 함 수 를 눌 러 넣 고 반대로 직접 눌 러 넣 습 니 다.
removeListener

if (listeners && listeners.length) {
  index = listeners.reduce((i, listener, index) => {
    return (typeof listener.callback == 'function' && listener.callback === callback && listener.vm == vm) ?
      i = index :
      i;
  }, -1);

  if (index > -1) {
    listeners.splice(index, 1);
    this.listeners.set(label, listeners);
    return true;
  }
}
return false;
여기 도 간단 합 니 다.이 사건 에 대응 하 는 반전 배열 을 가 져 옵 니 다.비어 있 지 않 으 면 제거 해 야 할 리 셋 을 찾 아 찾 은 후 바로 삭제 하고 새로운 리 셋 배열 을 원래 의 것 으로 덮어 쓰 면 됩 니 다.
emit

if (listeners && listeners.length) {
  listeners.forEach((listener) => {
    listener.callback.call(listener.vm,...args)
  });
  return true;
}
return false;
여기 가 바로 사건 을 감청 한 후에 이 사건 에 대응 하 는 리 셋 함 수 를 실행 하 는 것 입 니 다.여기 콜 을 주의 하 십시오.사건 을 감청 한 후에 우 리 는 vue 인 스 턴 스 의 데 이 터 를 수정 하거나 방법 을 호출 해 야 할 수도 있 습 니 다.vue 를 사용 한 학생 들 은 우리 가 모두 this.xxx 로 호출 된 것 을 알 고 있 기 때문에 반드시 리 셋 함수 의 this 를 vue 인 스 턴 스 로 가 리 켜 야 합 니 다.리 셋 사건 을 저장 할 때 도 vue 인 스 턴 스 를 저장 해 야 하 는 이유 다.
Observer.js

constructor(connection, store) {
  //       ,      connection     
  //                   socket  ,      url
  if(typeof connection == 'string'){
    this.Socket = Socket(connection);
  }else{
    this.Socket = connection
  }

  //      vuex store     store   mutations actions
  //          oberver   
  if(store) this.store = store;

  //   ,  !
  this.onEvent()

}

이 Observer.js 에 도 Observer 의 class 가 쓰 여 있 습 니 다.이상 은 구조 함수 입 니 다.구조 함수 의 첫 번 째 일 은 connection 이 문자열 인지 아 닌 지 를 판단 하 는 것 입 니 다.socket 인 스 턴 스 를 구축 하 는 것 입 니 다.그렇지 않 으 면 socket 의 인 스 턴 스 일 것 입 니 다.그리고 대상 인 스 턴 스 에 직접 마 운 트 합 니 다.사실 여기 서 저 는 매개 변 수 를 엄격하게 검사 할 수 있다 고 생각 합 니 다.예 를 들 어 문자열 이 이상 하 게 도 불법 url 로 들 어 갈 수 있 습 니 다.그 렇 죠?이 럴 때 판단 해서 error 알림 을 던 져 도 좋 지만 이렇게 지루 한 사람 은 없 을 거 예요.2333.그리고 store 에 들 어 오 면 대상 인 스 턴 스 에 도 걸 어 주세요.결국 감청 사건 이 시 작 됐 습 니 다.온 이벤트 의 논 리 를 살 펴 보 겠 습 니 다.

  onEvent(){
    //           ,packet.data     
    //       ,            
    //    emit               
    //       vuex store,         passToStore,  passToStore   
    var super_onevent = this.Socket.onevent;
    this.Socket.onevent = (packet) => {
      super_onevent.call(this.Socket, packet);

      Emitter.emit(packet.data[0], packet.data[1]);

      if(this.store) this.passToStore('SOCKET_'+packet.data[0], [ ...packet.data.slice(1)])
    };

    //              ,           ,                 ?
    //            this
    //            ,      ,                 this
    let _this = this;

    ["connect", "error", "disconnect", "reconnect", "reconnect_attempt", "reconnecting", "reconnect_error", "reconnect_failed", "connect_error", "connect_timeout", "connecting", "ping", "pong"]
      .forEach((value) => {
        _this.Socket.on(value, (data) => {
          Emitter.emit(value, data);
          if(_this.store) _this.passToStore('SOCKET_'+value, data)
        })
      })
  }

여기 가 바로 onevent 라 는 함 수 를 다시 불 러 오 는 것 과 유사 합 니 다.사건 을 감청 한 후에 데 이 터 를 뜯 어서 리 셋 과 store 에 전달 하 라 고 알 립 니 다.대체적인 논 리 는 이렇다.그리고 이 코드 는 두 부분 이 있 는데 첫 번 째 부분 과 두 번 째 부분의 논 리 는 기본적으로 같다.그냥 따로 써 요.사실 저도 잘 모 르 겠 어 요.필요 하 다 면 첫 번 째 부분의 작법 은 두 번 째 부분의 사건 을 감청 할 수 없 을 것 같 아서 따로 감청 해 야 해 요.)마지막 으로 패스 토 스토어 가 하나 밖 에 남지 않 았 습 니 다.사실 쉽게 알 수 있 습 니 다.

 passToStore(event, payload){
   //        SOCKET_        
   if(!event.startsWith('SOCKET_')) return

   //     vuex store  mutations
   for(let namespaced in this.store._mutations) {
     //         ,  store  module   namespaced ,  mutation       xxx/
     //    mutation      
     let mutation = namespaced.split('/').pop()
     //            ,      commit     mutation
     //    ,mutation        SOCKET_    
     if(mutation === event.toUpperCase()) this.store.commit(namespaced, payload)
   }
   //       
   for(let namespaced in this.store._actions) {
     let action = namespaced.split('/').pop()

     //        action      socket_   
     if(!action.startsWith('socket_')) continue

     //             
     let camelcased = 'socket_'+event
         .replace('SOCKET_', '')
         .replace(/^([A-Z])|[\W\s_]+(\w)/g, (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase())

     //   action     ,      action
     if(action === camelcased) this.store.dispatch(namespaced, payload)
   }
 }

passToStore 는 사실 두 가지 일 을 하 는 것 입 니 다.하 나 는 이 사건 에 대응 하 는 mutation 을 가 져 온 다음 에 commt 를 시작 하 는 것 입 니 다.하 나 는 이 사건 에 대응 하 는 action 을 가 져 온 다음 에 dispatch 입 니 다.다만 여기 서 의 실현 은 mutations 와 actions 의 명명 에 요구 가 있 습 니 다.예 를 들 어 mutations 의 명명 은 반드시 SOCKET 이 어야 합 니 다.처음에 action 은 socket처음에는 낙타 봉 식 으로 명명 해 야 한다.
마지막.
우선,이 소스 코드 는 좀 간단 하지 않 습 니까?하하 하,하지만 도움 을 줄 수 있어 서 저도 좋 은 것 같 습 니 다.
그리고 위 에 제 가 말 한 것 이 맞다 면 여기 로 오 세 요issue아니면 직접 댓 글 을 달 아 주세요.
마지막
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기