; 코드를 이해하기 쉽게 함수로 분리하기
io.on('connection', (sock) => {
console.log('새로운 소켓이 연결됐어요!');
sock.on('BUY', (data) => {
const emitData = {
...data,
date: new Date().toISOString(),
};
io.emit('BUY_GOODS', emitData);
});
... // 생략
sock.on('disconnect', () => {
console.log(sock.id, '연결이 끊어졌어요!');
});
});
io.on('connection', (sock) => {
const { watchBuying, watchByebye } = initSocket(sock);
watchBuying();
watchByebye();
});
io.on('connection', ~~~~
)~~~ = initSocket(sock);
)watchBuying();
)watchByebye();
)// app.js
function initSocket(sock) {
console.log('새로운 소켓이 연결됐어요!');
// 특정 이벤트가 전달됐는지 감지할 때 사용될 함수
function watchEvent(eventName, func) {
sock.on(eventName, func);
}
// 연결된 모든 클라이언트에 데이터를 보낼때 사용될 함수
function sendMessageAll(eventName, data) {
io.emit(eventName, data);
}
return {
watchBuying: () => {
watchEvent('BUY', (data) => {
const emitData = {
...data,
date: new Date().toISOString(),
};
notifyEveryone('BUY_GOODS', emitData);
});
},
watchByebye: () => {
watchEvent('disconnect', () => {
console.log(sock.id, '연결이 끊어졌어요!');
});
},
};
}
func
는 sock.on에 있던 (data)부터의 전체 함수 부분을 뜻함
sock.on(eventName, func) == sock.on("BUY", (data) => ... )
data
는 sock.on에 있던 모든 data 부분을 뜻함
io.emit("BUY_GOODS", emitData) == io.emit(eventName, data)
반환해주기 위해 return을 사용하며, 객체분해구조할당의 경우는 변수명과 실제 return되는 객체의 키 값이 일치해야 한다.
const { watchBuying, watchByebye }
==watchBuying: () =>
&watchByebye: () =>
이렇게 코드를 읽기 쉽도록 원래 있던 코드를 분리하면서, 새로운 함수를 만들어 나가는 과정을 "추상화"한다고 표현합니다!
이렇게 추상화 된 코드는 보통 역할에 맞는 파일에 묶여서 관리되는데요, 바로 해보겠습니다!
; 특정 역할을 하는 코드들은 묶어서 파일로 분리!
일단, initSocket
함수와 io.on('connection', ~~~)
처럼 생긴 소켓 연결과 관련된 코드를 따로 분리해볼까요?
차근차근 따라해주세요!
소켓 관련된 코드만 따로 정리해둘 socket.js
파일 만들기
initSocket
함수와 io.on('connection', ~~~)
처럼 생긴 소켓 연결과 관련된 코드를 **app.js**
파일에서 **socket.js**
파일로 옮기기
initSocket
함수가 const io = socketIo(http);
객체를 필요로 하니 이 코드도 그대로 옮깁니다!
이 코드에서는 socket.io 모듈을 사용하기 때문에 해당 모듈을 호출하는 const socketIo = require('socket.io')
도 옮깁니다.
const io = socketIo(http);
에서 http 객체도 필요하니 **app.js**
에서 http 객체를 모듈로 내보내줍니다!
http 객체를 내보낼때는 **app.js**
에서 module.exports = http;
코드를 통해서 내보냅니다.
socket.js
파일에서 **app.js**
파일이 내보내준 http 객체를 가져와서 사용하도록 해줍니다!
app.js
를 실행을 해보면, 왼쪽 하단의 socket 메시지가 뜨지 않는 것을 확인할 수 있다.
socket.js
실행 시 소켓이 연결되었다는 메시지를 확인할 수 있는데, 매번 socket.js
을 실행할 수 없으므로 조치를 취해야 한다.
=> server.js
파일을 생성하여 socket.js
와 app.js
의 기능을 분리해 주어야 한다.
server.js
파일을 생성합니다.
app.js
파일에서는 서버를 켜지 않도록 http.listen
코드를 제거한 후, server.js로 이동해준다.
**server.js**
파일에서 **app.js**
와 socket.js
파일을 참조합니다.
const http = require('./app');
require('./socket'); // 이렇게 불러오기만 해도 소켓에 연결이 됩니다.
http.listen(8080, () => {
console.log('서버가 요청을 받을 준비가 됐어요');
});
이제 server.js 파일을 실행해야만 서버가 켜지며, 서버가 켜질때는 항상 소켓까지 연결 준비가 완료된 상태가 되었습니다!!
- socket.js
const socketIo = require('socket.io'); // 1. 모듈 불러오기
const http = require('./app');
const io = socketIo(http); // 3. http 객체를 Socket.io 모듈에 넘겨서 소켓 핸들러 생성
// 4. 소켓 연결 이벤트 핸들링
io.on('connection', (sock) => {
const { watchBuying, watchByeBye } = initSocket(sock);
watchBuying();
watchByeBye();
});
function initSocket(sock) {
console.log('새로운 소켓이 연결되었어요!');
// sock.on을 대신해서, 어떤 역할을 하는지 추상화 한 함수
function watchEvent(eventName, func) {
sock.on(eventName, func);
}
// 현재 접속한 모든 클라이언트 들에게 메시지를 전송하는 구나 라고 이해할 수 있는 함수
function sendMessageAll(eventName, data) {
io.emit(eventName, data);
}
return {
watchBuying: () => {
watchEvent('BUY', (data) => {
const emitData = {
nickname: data.nickname, // 서버가 보내준 구매자 닉네임
goodsId: data.goodsId, // 서버가 보내준 상품 데이터 고유 ID
goodsName: data.goodsName, //서버가 보내준 구매자가 구매한 상품 이름
date: new Date().toISOString(), //서버가 보내준 구매 일시
};
sendMessageAll('BUY_GOODS', emitData);
});
},
watchByeBye: () => {
watchEvent('discount', () => {
console.log(sock.id, '연결이 끊어졌어요!');
});
},
};
}
- app.js
// app.js
module.exports = http;
- server.js
const http = require("./app");
require("./socket");
// 5. app 대신 http 객체로 서버 열기
http.listen(8080, () => {
console.log('서버가 요청을 받을 준비가 됐어요!');
});