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

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

封装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管理器,可以有效处理连接、消息传递和自动重连等操作,使开发过程更加简洁和灵活。

推荐文章

Go 1.23 中的新包:unique
2024-11-18 12:32:57 +0800 CST
Rust开发笔记 | Rust的交互式Shell
2024-11-18 19:55:44 +0800 CST
详解 Nginx 的 `sub_filter` 指令
2024-11-19 02:09:49 +0800 CST
用 Rust 构建一个 WebSocket 服务器
2024-11-19 10:08:22 +0800 CST
如何使用go-redis库与Redis数据库
2024-11-17 04:52:02 +0800 CST
Vue3中的组件通信方式有哪些?
2024-11-17 04:17:57 +0800 CST
Vue3 vue-office 插件实现 Word 预览
2024-11-19 02:19:34 +0800 CST
在Rust项目中使用SQLite数据库
2024-11-19 08:48:00 +0800 CST
CSS 实现金额数字滚动效果
2024-11-19 09:17:15 +0800 CST
Nginx 性能优化有这篇就够了!
2024-11-19 01:57:41 +0800 CST
api远程把word文件转换为pdf
2024-11-19 03:48:33 +0800 CST
JavaScript 流程控制
2024-11-19 05:14:38 +0800 CST
JavaScript 上传文件的几种方式
2024-11-18 21:11:59 +0800 CST
在 Rust 生产项目中存储数据
2024-11-19 02:35:11 +0800 CST
PHP设计模式:单例模式
2024-11-18 18:31:43 +0800 CST
资源文档库
2024-12-07 20:42:49 +0800 CST
Vue 中如何处理跨组件通信?
2024-11-17 15:59:54 +0800 CST
jQuery中向DOM添加元素的多种方法
2024-11-18 23:19:46 +0800 CST
Golang - 使用 GoFakeIt 生成 Mock 数据
2024-11-18 15:51:22 +0800 CST
Golang中国地址生成扩展包
2024-11-19 06:01:16 +0800 CST
程序员茄子在线接单