Vue Socket.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.jsEmitter.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아니면 직접 댓 글 을 달 아 주세요.
마지막
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Vue Render 함수로 DOM 노드 코드 인스턴스 만들기render에서createElement 함수를 사용하여 DOM 노드를 만드는 것은 직관적이지 않지만 일부 독립 구성 요소의 디자인에서 특수한 수요를 충족시킬 수 있습니다.간단한 렌더링 예는 다음과 같습니다. 또한 v...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.