WebSocket 前端實作筆記 🚀

專案背景

  • 前端技術棧:Vue3

組員:「欸!為什麼要寫一個 websocket.js?」

開發的時候養成好習慣超重要!(我覺得我很棒)

與其在每個需要用到 WebSocket 的地方都重新寫一次邏輯, 不如把它包成一個服務類別,這樣哪裡要用就 import 進來用就好啦~

類別怎麼設計的 🤔

首先會需要三個重要的屬性:

constructor() {
    this.ws = null            // WebSocket 連接實例
    this.isConnected = false  // 追蹤連接狀態
    this.messageHandlers = new Map()  // 用來存放各種消息的處理函數
}

為什麼要用 Map 來存處理函數? 因為超級方便的啊!比如說:

  • 想處理 「加入購物車」 的消息? → 存一個 handler 進 Map

  • 想處理 「移除商品」 的消息? → 再存一個 handler

  • 收到消息時查一下 Map 就知道要用哪個 handler 了

  • 比寫一堆 if-else 來得清爽多了!

重要的方法們 👾

connect() - 建立連接

connect() {
    // 建立 WebSocket 連接
    this.ws = new WebSocket(`${import.meta.env.VITE_WEBSOCKET_URL}`)
    
    // 連接成功
    this.ws.onopen = () => {
        this.isConnected = true
        console.log('耶~連上了!')
    }
    
    // 收到消息
    this.ws.onmessage = (event) => {
        try {
            const data = JSON.parse(event.data)
            const handler = this.messageHandlers.get(data.type)
            
            if (handler) {
                handler(data)
            } else {
                console.warn(`咦?沒有處理 ${data.type} 的函數耶`)
            }
        } catch (error) {
            console.error("哎呀!解析消息失敗了:", error)
        }
    }

    // 斷開連接
    this.ws.onclose = () => {
        this.isConnected = false
        console.log('斷線了QQ')
    }

    // 連接出錯
    this.ws.onerror = (error) => {
        console.error("糟糕!連接出錯了:", error)
        this.isConnected = false
    }
}

onMessage() - 註冊消息處理函數

onMessage(type, handler) {
    // 簡單!把處理函數存進 Map
    this.messageHandlers.set(type, handler)
}

sendMessage() - 發送消息

sendMessage(type, data) {
    // 檢查一下連接狀態
    if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
        console.error("欸欸!還沒連上不能發送啦")
        return
    }

    try {
        const message = JSON.stringify({ type, data })
        this.ws.send(message)
    } catch (error) {
        console.error("糟糕!發送失敗了:", error)
    }
}

disconnect() - 斷開連接

disconnect() {
    if (this.ws) {
        this.ws.close()
        this.ws = null
        this.isConnected = false
    }
}

怎麼讓整個專案都用同一個 WebSocket?

單例模式!就是把這個服務包成一個實例然後導出

export const webSocketService = new WebSocketService()

這樣在其他地方要用的時候就:

import { webSocketService } from './websocket'

搞定!整個專案都會用到同一個 WebSocket 實例,超方便的~

之後可以加強的地方 💪

  • 加個重連機制:斷線自動重連

  • 加個心跳檢測:確保連接還活著

  • 處理離線時的消息:可以先存起來等連上再發

  • 錯誤重試:發送失敗自動重試幾次

好啦!這樣就完成了一個基本的 WebSocket 服務類別,之後在共享購物車頁面就可以直接 import 來用~ 🎉

Last updated