🗂️ 파일 시스템
1. Node.js의 비동기 메서드
2. 버퍼와 스트림
- 버퍼 : 메모리에서 직접 바이트 데이터 처리
- 한 번에 메모리에 올릴 때 유용
- 대용량 데이터에는 비효율적
- ex) fs 모듈 -
readFile
- 스트림 : 청크 단위로 데이터를 처리하여 메모리 사용량 절약
- 읽기 스트림 / 쓰기 스트림
- ex) fs 모듈 -
createReadStream
, createWriteStream
3. 버퍼를 base64로 인코딩
- 읽어온 이미지 파일을 base64 인코딩 -> 웹 브라우저에 직접 렌더링 가능
- base64 : 바이너리 데이터를 문자열로 변환하는 방법
- 이메일이나 JSON 데이터로 이미지 전송할 때 유용
fs.readFile('example.jpg', (err, data) => {
if (err) throw err;
const base64Image = data.toString('base64');
console.log('이미지:', base64Image);
});
🎉 이벤트
- Node.js는 싱글 스레드 이벤트 루프로 비동기 작업 처리 (여러 작업 동시 처리 가능)
- 비동기 처리로 이벤트 큐에 등록, 이벤트 루프는 다른 작업 수행
- 각 작업이 완료될 때 이벤트 발생 -> 바인딩된 콜백 함수 실행
- 고성능 네트워크 애플리케이션 구축에 유리 (IO 작업)
이벤트가 왜 필요한데?
- 이벤트는 콜백 함수가 비동기적으로 실행
- 반면 함수는 작업이 완료될 때까지 대기 => 비동기 처리 어려움
1. events 모듈
events
모듈 (내장 객체)
events
모듈의 EventEmitter
클래스로 이벤트 생성 및 처리
- 이벤트 정의 & 발생 & 처리 리스너 연결
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
2. 이벤트 생성 & 리스너 등록
on
메서드 : 이벤트 리스너 등록
emit
메서드 : 이벤트 발생
- 특정 이벤트에 여러 개의 리스너 등록 가능(이벤트 발생 시, 순서대로 호출)
myEmitter.on("greet", (name) => {
console.log(`안녕하세요. ${name}님!`);
});
myEmitter.emit('greet', '영희');
myEmitter.on('asyncEvent', async () => {
const data = await Promise.resolve();
console.log(data);
});
myEmitter.emit('asyncEvent');
on 메서드 & once 메서드
on(event, listener)
: 이벤트가 여러번 발생할 때마다 호출
once(event, listener)
: 첫 이벤트만 듣고 이후 이벤트는 듣지 않음
- 궁금) 첫 이벤트 발생 후, 같은 이벤트와 콜백함수를 다시 등록하면?
3. 이벤트 리스너 삭제
removeListener(event, listener)
: 특정 이벤트에 등록된 리스너 제거
removeAllListeners(event)
: 특정 이벤트에 연결된 모든 리스너 제거
4. 에러 처리
- 에러 이벤트 리스너를 정의하고 에러가 발생하면 에러 이벤트를 발생시키는 방식
myEmitter.on('error', (err) => {
console.error('에러 발생:', err.message);
});
myEmitter.on('someEvent', () => {
myEmitter.emit('error', new Error('명시적인 에러 발생'));
});
5. 이벤트 루프 & 비동기 작업
process.nextTick(() => console.log('nextTick 실행'));
setImmediate(() => console.log('setImmediate 실행'));
console.log('일반 코드 실행');
일반 코드 실행
nextTick 실행
setImmediate 실행
웹 소켓
1. Websocket 모듈
const Websocket = require("ws");
const wss = new Websocket.Server({ port: 8080 });
2. 클라이언트 접속
- connection 이벤트 : 클라이언트가 접속했을 때 발생
- 웹소켓 서버에서 기본적으로 제공하는 이벤트
- emit 없어도 자체적으로 발생
wss.on("connection", (ws) => {
ws.id = new Date().getTime().toString().slice(-3);
console.log("연결됐음");
ws.on("message", (message) => {
console.log(`${ws.id}로부터 메시지 수신: ${message}`);
wss.clients.forEach((client) => {
if (client !== ws) {
client.send(message.toString());
}
});
ws.on("close", () => {
console.log("연결 종료");
});
3. 클라이언트에서는
const socket = new WebSocket("ws://localhost:8080");
socket.addEventListener("open", function() {
console.log("서버와 연결");
});
socket.addEventListener("message", function(e) {
console.log(e.data);
});
something.addEventListener("이벤트", function() {
socket.send("메시지");
}
🎢 Express
1. express 모듈
- HTTP 요청의 경로 & HTTP 메서드를 통해 쉽게 API 요청 가능 (간단!)
const express = require("express");
const app = express();
const port = 5000;
2. 미들웨어 등록
- 요청이 발생되기 전에 먼저 거쳐 가는 부분
- 서버가 요청을 처리하기 전에 실행할 기능 설정
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
3. API 요청
GET : 항목 조회
app.get('/path/:id', (req, res) => { ... });
POST : 새 항목 추가
app.post('/path', (req, res) => { ... });
PUT : 전체 항목 업데이트
app.put('/path/:id', (req, res) => { ... });
PATCH : 부분 업데이트
app.patch('/path/:id', (req, res) => { ... });
DELETE : 항목 삭제
app.delete('/path/:id', (req, res) => { ... });
OPTIONS : CORS 및 허용 메서드 확인
- options 메서드 : 클라이언트가 서버에 어떤 HTTP 메서드를 지원하는지 확인하려고 할 때 사용
- CORS 요청이나 프리플라이트 요청에 의해 자동으로 발생
app.options('/items', (req, res) => {
res.set('Allow', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
res.sendStatus(204);
});
4. 서버 시작
app.listen(PORT, () => {
console.log(`Server running :${PORT}`);
});
✏️ 메모
- nodemon => 서버를 실행하면서 코드를 수정하면 자동으로 서버 재시작
- 설치 :
npm install nodemon
- 실행 :
npx nodemon 파일.js
- 웹소켓에 클라이언트가 엄청나게 발생하면 문제가 없나?
- 연결로는 문제 없음
- 단, 받은 메세지에 대한 로직 처리의 부담은 존재
- 실무에서는 연결을 잘게 쪼개 각 서버에 분산
📌 출처
수코딩(https://www.sucoding.kr)