Сборка живого чата на клиенте
Складываем события и send() в полноценный клиент чата (концептуально).
Клиент реалтайма — код в браузере, который держит WebSocket, шлёт действия пользователя серверу и отображает входящие события.
Скелет клиента
Соберём типичную обвязку: подключение, отправка по нажатию кнопки, отрисовка входящих сообщений. Код требует живого сервера, поэтому он для чтения:
// Браузер: клиент чата
const socket = new WebSocket("wss://example.com/chat");
socket.onopen = () => {
setStatus("онлайн");
};
socket.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === "chat") {
addLine(msg.user + ": " + msg.text);
}
};
socket.onclose = () => {
setStatus("оффлайн");
};
// при нажатии кнопки «Отправить»
function sendChat(text) {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({ type: "chat", text: text }));
}
}Поток данных
[поле ввода] --клик «Отправить»--> sendChat()
|
send() ---------> СЕРВЕР
|
(сервер раздаёт всем) <----+
|
onmessage <--- фрейм с чужим сообщением
|
addLine() --> [лента чата]Защита от отправки в закрытый канал
Перед send() всегда проверяем readyState: если канал не OPEN (идёт реконнект, обрыв), отправка либо бросит ошибку, либо потеряется. Хороший клиент в таком случае ставит сообщение в очередь и шлёт после восстановления.
Как работает под капотом
Важно понять асимметрию: ваше сообщение и чужие приходят разными путями. Когда вы жмёте «Отправить», вы не дорисовываете строку сразу — вы шлёте её серверу. Сервер раздаёт её всем участникам, включая вас, и только тогда сработает onmessage и строка появится в ленте. Так все видят одинаковый порядок сообщений, заданный сервером, а не локальной гонкой.
Частые ошибки
- Рисовать своё сообщение локально до ответа сервера. Тогда порядок у разных людей разойдётся; либо ждите эхо от сервера, либо делайте «оптимистичный» рендер с последующей синхронизацией.
- Не обрабатывать неизвестные типы сообщений. Сервер может прислать
type, которого клиент не знает; игнорируйте такие, а не падайте. - Забыть статус соединения. Пользователь должен видеть «онлайн/оффлайн», иначе непонятно, доходят ли его сообщения.
Итоги
- Клиент держит сокет, шлёт действия через
send()и рисует входящие вonmessage. - Перед отправкой проверяйте
readyState === OPEN. - Ваше сообщение возвращается эхом от сервера — так гарантируется единый порядок для всех.
- Показывайте статус соединения и игнорируйте неизвестные типы сообщений.