添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

The purpose of this article is to understand the basics of websockets and cache with a common known example : a Chat.

Usually, a Chat have to be really reactive with very good performance. There are many ways to achieve different levels of performance.

In this article, we'll build a basic sample high-performance Chat together with Typescript, Redis and Websockets. I'll guide you step-by-step as if I was doing it with you.

First, let's take a look at our architecture.

  • To the keep things simple, we'll be doing the frontend in plain HTML/JS without framework
  • The Nodejs server will be written with express as it's most known.
  • A Redis server to cache messages
  • Tips : If you wanna enhance performance further, you can opt for another framework like fastify, websocket.io, uWebSocket or whatever you want. We'll stay with express as it's well commonly known.

    const client = createClient ({ url : ' redis://redis:6379 ' // we'll create the docker image later client . on ( ' error ' , ( err ) => { console . error ( ' Redis Client Error ' , err ); client . connect (); export default client ;
    import express from "express";
    import { WebSocketServer } from "ws";
    import redisClient from "./redisClient";
    import { ChatMessage } from "./chatMessage";
    const app = express();
    const port = 3000;
    app.get("/", (req, res) => {
      res.send("Chat server is running");
    const server = app.listen(port, () => {
      console.log(`Web server is running on http://localhost:${port}`);
    const wss = new WebSocketServer({ server });
    wss.on("connection", (ws) => {
      console.log("Client connected");
      // Send chat history to new client
      redisClient.lRange("chat_message", 0, -1).then(
        (messages) => {
          messages.forEach((message) => {
            ws.send(message);
        (error) => {
          console.error("Error retrieving messages from Redis", error);
          return;
      ws.on("message", (data) => {
        const message: ChatMessage = JSON.parse(data.toString());
        message.timestamp = Date.now();
        const messageString = JSON.stringify(message);
        // Save message to Redis
        redisClient.rPush("chat_messages", messageString);
        redisClient.lTrim("chat_messages", -100, -1); // Keep only the last 100 messages
        // Broadcast message to all clients
        wss.clients.forEach((client) => {
          if (client.readyState === ws.OPEN) {
            client.send(messageString);
      ws.on("close", () => {
        console.log("Client disconnected");
    console.log("WebSocket server is running on ws://localhost:3000");
        Enter fullscreen mode
        Exit fullscreen mode
    
  • First, we setup the Web and WebSocket servers.
  • Second, on the websocket connection, we pull the Chat history from redis
  • Third, we listen for new messages and record them in redis, keeping only the 100 last message anytime
  • Fourth, we broadcast each messages to all the connected clients of the Chat
  • If you wanna go further, you can implement an observer pattern where each websocket client is an observer. But for now, let's keep the things simple.

    For barrels fans, don’t forget to add your app entrypoint in ./src/index.ts :

    import './server';
        Enter fullscreen mode
        Exit fullscreen mode
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Chat</title>
    </head>
      <div id="chat">
        <ul id="messages"></ul>
        <input id="username" placeholder="Username">
        <input id="message" placeholder="Message">
        <button onclick="sendMessage()">Send</button>
      <script>
        const ws = new WebSocket('ws://localhost:3000');
        const messages = document.getElementById('messages');
        ws.onmessage = (event) => {
          const message = JSON.parse(event.data);
          const li = document.createElement('li');
          li.textContent = `[${new Date(message.timestamp).toLocaleTimeString()}] ${message.username}: ${message.message}`;
          messages.appendChild(li);
        function sendMessage() {
          const username = document.getElementById('username').value;
          const message = document.getElementById('message').value;
          ws.send(JSON.stringify({ username, message }));
      </script>
    </body>
    </html>
        Enter fullscreen mode
        Exit fullscreen mode
    
  • We setup the html document to have the needed fields and button to send a message
  • We setup the websocket connection with the server
  • We publish every message to the websocket anytime the button is pressed calling the function sendMessage()
  • Built on Forem — the open source software that powers DEV and other inclusive communities.

    Made with love and Ruby on Rails. DEV Community © 2016 - 2024.