编程 封装WebSocket消息推送,干翻Ajax轮询方式

2024-11-18 20:10:17 +0800 CST views 727

封装WebSocket消息推送,干翻Ajax轮询方式

前言

使用AJAX和WebSocket都可以实现消息推送,但它们在实现方式和适用场景上有所不同。本文将对这两种技术的实现进行简要说明,并介绍如何封装一个WebSocket消息推送管理器,替代传统的AJAX轮询方式。

AJAX 实现消息推送

轮询(Polling)

轮询是指客户端定期向服务器发送请求以检查是否有新消息。尽管简单易用,但频繁的无效请求会带来性能开销。

function pollForMessages() {
    $.ajax({
        url: '/messages',
        method: 'GET',
        success: function(data) {
            console.log(data); // 处理接收到的消息
            setTimeout(pollForMessages, 5000); // 每5秒轮询一次
        },
        error: function() {
            setTimeout(pollForMessages, 10000); // 请求失败时等待更长时间后重试
        }
    });
}

// 开始轮询
pollForMessages();

长轮询(Long-Polling)

长轮询是轮询的改进版本,客户端发起请求后,服务器在有新消息时才会返回响应,否则保持连接。尽管能减少无效请求,但仍存在延迟问题。

WebSocket 实现消息推送

WebSocket是一种全双工的通信协议,允许服务器主动向客户端推送消息。相比AJAX的请求-响应模式,WebSocket的通信更为高效。

var socket = new WebSocket('ws://your-server-url');

socket.onopen = function(event) {
    socket.send('Hello Server!');
};

socket.onmessage = function(event) {
    console.log('Received:', event.data);
};

socket.onerror = function(error) {
    console.error('WebSocket Error:', error);
};

socket.onclose = function(event) {
    console.log('WebSocket is closed now.');
};

WebSocket 消息推送封装

概念类比

想象你是一个快递员,负责将消息包裹(WebSocket消息)送到不同的收件人(客户端)。你通过一辆智能快递车(WebSocket连接)传递消息,并记录每个收件人的信息。每次有新消息时,快递车会自动将包裹送达收件人,并在收到回复时立刻通知你。

WebSocketManager 设计思路

WebSocketMessenger负责管理和维护WebSocket连接,并通过封装实现对连接的控制、消息的发送和接收,以及重连机制。

WebSocketManager 类

class WebSocketManager {
  constructor(url = null, userId = null, receiveMessageCallback = null) {
    this.socket = null;
    this.sendTimeObj = null;
    this.reconnectTimeObj = null;
    this.reconnectTimeDistance = 5000;
    this.maxReconnectAttempts = 10;
    this.reconnectAttempts = 0;
    this.id = userId;
    this.url = url;
    this.receiveMessageCallback = receiveMessageCallback;
  }

  // 开启WebSocket连接
  async start() {
    if (this.url && this.id) {
      this.connectWebSocket();
    } else {
      console.error('WebSocket errors: 请传入连接地址和用户id');
    }
  }

  // 创建WebSocket连接
  connectWebSocket() {
    let id = `${this.id}-${Math.random()}`;
    this.socket = new WebSocket(this.url, id);

    this.socket.onopen = (event) => {
      this.startSendServe();
    };

    this.socket.onmessage = (event) => {
      this.receiveMessage(event);
    };

    this.socket.onclose = (event) => {
      clearTimeout(this.sendTimeObj);
      clearTimeout(this.reconnectTimeObj);
      if (this.reconnectAttempts < this.maxReconnectAttempts) {
        this.reconnectAttempts++;
        this.reconnectTimeObj = setTimeout(() => {
          this.connectWebSocket();
        }, this.reconnectTimeDistance);
      } else {
        this.reconnectAttempts = 0;
        console.error('WebSocketManager errors: Max reconnect attempts reached.');
      }
    };

    this.socket.onerror = (event) => {
      console.error('WebSocketManager error:', event);
    };
  }

  // 发送消息
  sendMessage(message) {
    if (this.socket.readyState === WebSocket.OPEN) {
      this.socket.send(message);
    } else {
      console.error('WebSocketManager error: WebSocket connection is not open.');
    }
  }

  // 接收消息处理
  receiveMessage(event) {
    console.log('receiveMessage:', event.data);
    this.receiveMessageCallback && this.receiveMessageCallback(event.data);
  }

  // 关闭WebSocket连接
  closeWebSocket() {
    this.socket.close();
    clearTimeout(this.sendTimeObj);
    clearTimeout(this.reconnectTimeObj);
    this.reconnectAttempts = 0;
  }
}

使用Demo

在页面中可以这样使用该封装类:

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebSocket Demo</title>
    <script src="./webSocketManager.js"></script>
    <script>
        const receiveMessage = (res) => {
            console.log('接收消息回调:', res);
        };
        const socketManager = new WebSocketManager('ws://localhost:3000', 'userid292992', receiveMessage);
        socketManager.start();
    </script>
</head>

总结

与传统的AJAX轮询相比,WebSocket提供了更加高效的消息推送方式。通过封装一个WebSocket管理器,可以有效处理连接、消息传递和自动重连等操作,使开发过程更加简洁和灵活。

推荐文章

Dropzone.js实现文件拖放上传功能
2024-11-18 18:28:02 +0800 CST
Vue3中的响应式原理是什么?
2024-11-19 09:43:12 +0800 CST
10个几乎无人使用的罕见HTML标签
2024-11-18 21:44:46 +0800 CST
小技巧vscode去除空格方法
2024-11-17 05:00:30 +0800 CST
支付轮询打赏系统介绍
2024-11-18 16:40:31 +0800 CST
IP地址获取函数
2024-11-19 00:03:29 +0800 CST
Nginx 实操指南:从入门到精通
2024-11-19 04:16:19 +0800 CST
Nginx 跨域处理配置
2024-11-18 16:51:51 +0800 CST
MySQL 优化利剑 EXPLAIN
2024-11-19 00:43:21 +0800 CST
Vue3中如何进行异步组件的加载?
2024-11-17 04:29:53 +0800 CST
HTML和CSS创建的弹性菜单
2024-11-19 10:09:04 +0800 CST
File 和 Blob 的区别
2024-11-18 23:11:46 +0800 CST
php常用的正则表达式
2024-11-19 03:48:35 +0800 CST
Vue 3 中的 Fragments 是什么?
2024-11-17 17:05:46 +0800 CST
Vue3中的v-for指令有什么新特性?
2024-11-18 12:34:09 +0800 CST
PHP设计模式:单例模式
2024-11-18 18:31:43 +0800 CST
一个收银台的HTML
2025-01-17 16:15:32 +0800 CST
js一键生成随机颜色:randomColor
2024-11-18 10:13:44 +0800 CST
什么是Vue实例(Vue Instance)?
2024-11-19 06:04:20 +0800 CST
Vue中如何处理异步更新DOM?
2024-11-18 22:38:53 +0800 CST
程序员茄子在线接单