본 문서에서는 Socket.IO를 사용하여 실시간 채팅 애플리케이션을 구현하는 방법과, 사용자 경험을 향상시키기 위해 Optimistic Update 기법을 적용하는 방법에 대해 설명합니다. Optimistic Update는 사용자가 행동을 취했을 때, 서버의 응답을 기다리지 않고 UI를 미리 업데이트하는 기법으로, 반응성이 높은 사용자 경험을 제공합니다.
Optimistic Update는 사용자 인터페이스(UI) 설계에서 사용되는 기법으로, 네트워크 요청의 결과(성공 또는 실패)를 기다리지 않고, 사용자의 액션이 성공할 것으로 "낙관적"으로 가정하고 UI를 미리 업데이트하는 방식입니다. 이 기법은 특히 네트워크 지연이나 서버 응답 시간으로 인해 사용자 경험이 저하될 수 있는 웹 애플리케이션에서 유용합니다.
Frontend: HTML, JavaScript
Backend: Node.js, Express
Real-time Communication: Socket.IO
Node.js와 Express를 사용하여 기본 서버를 설정하고, Socket.IO를 통해 실시간 통신 기능을 추가합니다.
import express from 'express';
import { createServer } from 'node:http';
import { Server } from 'socket.io';
const app = express();
const server = createServer(app);
const io = new Server(server);
io.on('connection', socket => {
socket.on('send_message', (data, callback) => {
io.emit('receive_message', data);
callback({ status: 'ok' });
});
});
server.listen(3000, () => {
console.log('server running at http://localhost:3000');
});
HTML과 JavaScript를 사용하여 사용자 인터페이스를 구성합니다. 사용자가 메시지를 보내면, Socket.IO를 통해 서버에 이를 전송합니다.
const socket = io("http://localhost:3000");
function sendMessage() {
var message = document.getElementById('message_input').value;
addMessageToUI(message, true);
socket.emit('send_message', message, response => {
// ...
});
}
function addMessageToUI(message, isOptimistic = false) {
// ...
}
socket.on('receive_message', function (message) {
addMessageToUI(message);
});
사용자가 메시지를 보낼 때, 서버의 응답을 기다리지 않고 즉시 UI를 업데이트합니다. 이는 사용자가 자신의 행동에 대한 즉각적인 피드백을 받을 수 있게 하여 사용자 경험을 개선합니다.
function addMessageToUI(message, isOptimistic = false) {
var messages = document.getElementById('messages');
var li = document.createElement('li');
li.textContent = message;
if (isOptimistic) {
li.style.opacity = '0.5';
}
messages.appendChild(li);
}
각 사용자가 보낸 메시지를 구분하기 위해, 메시지와 함께 사용자 식별 정보를 전송합니다. 이를 통해 서버로부터 받은 메시지가 현재 사용자의 것인지 판별하여, 이미 보낸 메시지는 UI에 다시 표시하지 않습니다.
socket.on('receive_message', function (data) {
if (data.userId === currentUserId) {
// 투명도를 다시 1로 변경
document.getElementById('messages').lastChild.style.opacity = '1';
return;
}
addMessageToUI(data.message);
});