轮询解决方案

概述

轮询的使用场景:

  • 股票 K 线图
  • 聊天
  • 重要通知,实时预警

这些场景都是都要实时性的。

http 是请求响应模式,一定需要先请求,后响应。

解决方案:

  • 短轮询:interval 定时发送请求。问题:大量无意义的请求(老舔狗了😭),频繁打开关闭连接,而且定时很难确定固定的时间。
  • 长轮询:发送请求,直接有响应后,才发送下一次请求。问题:客户端长时间没有响应,导致超时,断开 TCP 连接(解决方法是当超时了立即再发送一次请求 - 抛出异常再发请求);而且服务器没有响应的时候挂起请求也需要占用服务器资源。
  • Websocket:WebSocket也是建立在TCP协议之上的,利用的是TCP全双工通信的能力,使用WebSocket,会经历两个阶段:握手阶段、通信阶段。缺点也有:维持 tcp 连接需要耗费资源。

示例

一、WebSocket + 轮询 回退机制

1. 后端(Node.js 使用 ws 库实现 WebSocket)

安装依赖:

npm install express ws

创建 server.js

const express = require('express');
const WebSocket = require('ws');const app = express();
const port = 3000;// 使用 HTTP 服务作为静态文件服务器
app.use(express.static('public'));// 轮询 API 模拟
app.get('/api/data', (req, res) => {const data = { timestamp: Date.now(), message: 'Polling data' };res.json(data);
});// 创建 WebSocket 服务
const server = app.listen(port, () => {console.log(`Server listening on port ${port}`);
});const wss = new WebSocket.Server({ server });// WebSocket 连接处理
wss.on('connection', (ws) => {console.log('WebSocket client connected');// 模拟定时推送数据const intervalId = setInterval(() => {const data = { timestamp: Date.now(), message: 'WebSocket data' };ws.send(JSON.stringify(data));}, 2000);//10s 后断开连接setTimeout(() => {ws.close();}, 10000);ws.on('close', () => {console.log('WebSocket client disconnected');clearInterval(intervalId);});
});
2. 前端代码

创建 public/index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>WebSocket + Polling</title><script src="app.js" defer></script>
</head>
<body><h1>WebSocket + Polling 回退机制</h1><div id="output"></div>
</body>
</html>

创建 public/app.js

let websocket;
let pollingInterval = 5000; // 初始轮询间隔为5秒
let pollingTimeout;const outputDiv = document.getElementById('output');// 显示数据
function displayData(data) {const dataElement = document.createElement('p');dataElement.textContent = `时间戳: ${data.timestamp}, 消息: ${data.message}`;outputDiv.appendChild(dataElement);
}// 初始化 WebSocket 连接
function connectWebSocket() {websocket = new WebSocket('ws://localhost:3000');websocket.onopen = function() {console.log('WebSocket 连接成功');clearTimeout(pollingTimeout); // WebSocket 成功连接后停止轮询};websocket.onmessage = function(event) {const data = JSON.parse(event.data);console.log('接收到 WebSocket 数据:', data);displayData(data);};websocket.onclose = function() {console.log('WebSocket 连接断开,启动轮询');startPolling();};websocket.onerror = function(error) {console.error('WebSocket 错误:', error);websocket.close();};
}// 轮询函数
function startPolling() {fetch('/api/data').then(response => response.json()).then(data => {console.log('轮询获取的数据:', data);displayData(data);}).catch(error => {console.error('轮询错误:', error);}).finally(() => {// 动态调整轮询频率(可选择)pollingTimeout = setTimeout(startPolling, pollingInterval);pollingInterval = Math.min(pollingInterval * 2, 60000); // 最长间隔不超过60秒});
}// 页面加载时尝试建立 WebSocket 连接
window.onload = function() {connectWebSocket();
};
启动步骤:
  1. 在终端运行 node server.js
  2. 访问 http://localhost:3000/,页面会首先尝试通过 WebSocket 获取数据,10s 之后, WebSocket 连接断开则自动回退到轮询方式获取数据,然后可以看到不断向后端接口发送请求进行轮训。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


二、SSE + 轮询 回退机制

1. 后端(Node.js 使用原生 EventSource 实现 SSE)

安装依赖:

npm install express

创建 server.js

const express = require('express');
const app = express();
const port = 3000;// 使用 HTTP 服务作为静态文件服务器
app.use(express.static('public'));// 轮询 API 模拟
app.get('/api/data', (req, res) => {const data = { timestamp: Date.now(), message: 'Polling data' };res.json(data);
});// SSE 接口
app.get('/api/sse', (req, res) => {res.setHeader('Content-Type', 'text/event-stream');res.setHeader('Cache-Control', 'no-cache');res.setHeader('Connection', 'keep-alive');// 解决跨域res.setHeader('Access-Control-Allow-Origin', '*');const sendSSE = () => {const data = { timestamp: Date.now(), message: 'SSE data' };res.write(`data: ${JSON.stringify(data)}`);};const intervalId = setInterval(sendSSE, 2000);// 10s 后停止发送数据 关闭SSE连接setTimeout(() => {clearInterval(intervalId);res.end();}, 10000);// 当客户端断开连接时清除定时器req.on('close', () => {clearInterval(intervalId);});
});app.listen(port, () => {console.log(`Server listening on port ${port}`);
});
2. 前端代码

创建 public/index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>SSE + Polling</title><script src="app.js" defer></script>
</head>
<body><h1>SSE + Polling 回退机制</h1><div id="output"></div>
</body>
</html>

创建 public/app.js

let eventSource;
let pollingInterval = 5000; // 初始轮询间隔为5秒
let pollingTimeout;const outputDiv = document.getElementById('output');// 显示数据
function displayData(data) {const dataElement = document.createElement('p');dataElement.textContent = `时间戳: ${data.timestamp}, 消息: ${data.message}`;outputDiv.appendChild(dataElement);
}// 初始化 SSE 连接
function connectSSE() {eventSource = new EventSource('http://localhost:3000/api/sse');eventSource.onopen = function() {console.log('SSE 连接成功');clearTimeout(pollingTimeout); // SSE 成功连接后停止轮询};eventSource.onmessage = function(event) {const data = JSON.parse(event.data);console.log('接收到 SSE 数据:', data);displayData(data);};eventSource.onerror = function(error) {console.error('SSE 错误:', error);eventSource.close();startPolling(); // SSE 断开后启动轮询};
}// 轮询函数
function startPolling() {fetch('/api/data').then(response => response.json()).then(data => {console.log('轮询获取的数据:', data);displayData(data);}).catch(error => {console.error('轮询错误:', error);}).finally(() => {// 动态调整轮询频率pollingTimeout = setTimeout(startPolling, pollingInterval);pollingInterval = Math.min(pollingInterval * 2, 60000); // 最长间隔不超过60秒});
}// 页面加载时尝试建立 SSE 连接
window.onload = function() {connectSSE();
};
启动步骤:
  1. 在终端运行 node server.js
  2. 访问 http://localhost:3000/,页面会首先尝试通过 SSE 获取数据,若 SSE 连接断开则自动回退到轮询方式获取数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

贴一篇写的不错的文章:技术方案实践: 前端轮询方案实现 & 思考_前端轮询方式的实现-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/422831.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用Python创建目录或文件路径列表

在 Python 中&#xff0c;创建目录或生成文件路径列表通常涉及使用 os、os.path 或 pathlib 模块。下面是一些常见的任务和方法&#xff0c;用于在 Python 中创建目录或获取文件路径列表。 问题背景 在初始阶段的 Python 学习过程中&#xff0c;可能遇到这样的问题&#xff1a…

基于Boost库的搜索引擎开发实践

目录 1.项目相关背景2.宏观原理3.相关技术栈和环境4.正排、倒排索引原理5.去标签和数据清洗模块parser5.1.认识标签5.2.准备数据源5.3.编写数据清洗代码parser5.3.1.编写读取文件Readfile5.3.2.编写分析文件Anafile5.3.2.编写保存清洗后数据SaveHtml5.3.2.测试parser 6.编写索引…

无人机动力系统设计之电调芯片参数选型

无人机动力系统设计之电调芯片参数选型 1. 源由2. 关键因素2.1 电压范围2.2 电流处理能力2.3 控制方式2.4 PWM输出与分辨率2.5 通讯接口2.6 保护功能2.7 支持霍尔传感器与无传感器模式2.8 集成度与外围器件2.9 效率与散热2.10 市场供应与成本 3. 因素阐述3.1 PWM工作频率3.1.1 …

Seata

TC - 事务协调者 维护全局和分支事务的状态&#xff0c;驱动全局事务提交或回滚。 TM - 事务管理器 定义全局事务的范围&#xff1a;开启全局事务、提交或回滚全局事务。 RM - 资源管理器 管理分支事务处理的资源&#xff0c;向 TC 注册分支事务&#xff0c;报告分支事务的…

Chainlit集成LlamaIndex并使用通义千问模型实现AI知识库检索网页对话应用

前言 之前使用Chainlit集成Langchain并使用通义千问大语言模型的API接口&#xff0c;实现一个基于文档文档的网页对话应用。 可以点击我的上一篇文章《Chainlit集成Langchain并使用通义千问和智谱AI实现AI知识库检索网页对话应用》 查看。 本次将Langchain框架更改为LlamaInde…

Hive任务优化参数整理

Hive本身是个基于hdfs的结构化数据管理工具&#xff0c;虽然在后面的发展中允许底层接入其他的数据源&#xff0c;比如第三方数据服务这种基础架构&#xff0c;但是它从立意上来说&#xff0c;它不适合用来做高性能查询引擎&#xff0c;反而在传统离线数据仓库中它有着自身的优…

使用 Elastic 和 LM Studio 的 Herding Llama 3.1

作者&#xff1a;来自 Elastic Charles Davison, Julian Khalifa 最新的 LM Studio 0.3 更新使 Elastic 的安全 AI Assistant 能够更轻松、更快速地与 LM Studio 托管模型一起运行。在这篇博客中&#xff0c;Elastic 和 LM Studio 团队将向你展示如何在几分钟内开始使用。如果你…

校园生活点餐外卖配送到宿舍小程序源码系统 带完整的安装代码包以及搭建部署教程

系统概述 随着移动互联网的普及和校园生活的多元化&#xff0c;学生们对于线上点餐、外卖配送等服务的依赖度越来越高。然而&#xff0c;传统的校园餐饮服务模式往往存在效率低下、覆盖范围有限、信息不透明等问题&#xff0c;难以满足学生多样化的需求。因此&#xff0c;开发…

30万月变现3-6万,你也可以

30万月变现3-6万&#xff0c;你也可以 我相信&#xff0c;这些年我的IP还是吸引了不少的中产阶级关注我&#xff0c;什么叫中产阶级&#xff0c;就是兜里还是能随便掏出大几十大几百万的现金的&#xff0c;这群人&#xff0c;有着自己稳定的职业和收入来源&#xff0c;生活水平…

实例讲解电动汽车换挡控制策略及Simulink模型搭建方法

轻型电动汽车一般采用直驱的方式作为驱动方式&#xff0c;即不经过变速箱进行速比的调节&#xff0c;电机输出轴直接经过主减速器将动力传输至车轮。换挡器的换挡方式一般为VCU接收档位器的换挡请求后&#xff0c;根据整车当前状态判断换挡状态&#xff0c;最后输出当前档位状态…

已经30岁了,想转行从头开始现实吗?什么样的工作算好工作?

我是29岁那年&#xff0c;完成从转行裸辞副业的职业转型。 如果你把职业生涯看成是从现在开始30岁&#xff0c;到你退休那年&#xff0c;中间这么漫长的30年&#xff0c;那么30岁转行完全来得及&#xff1b; 如果你觉得必须在什么年纪&#xff0c;什么时间内必须完成赚到几十…

拯救手残党,一键转换季节天气变化效果图!

一键可转换四季或多种天气效果图 AI现在已经发展到这种程度了吗&#xff1f; 神采PromeAI也是卷起来了 以往通过【草图渲染】功能 就生成转化各种效果图 但这对用户来说还不够 又给大家上线了「场景转换器」功能 一键就能生成想要的各种时节场景的变化 一张效果图可以给…

机器学习之实战篇——MNIST手写数字0~9识别(全连接神经网络模型)

机器学习之实战篇——Mnist手写数字0~9识别&#xff08;全连接神经网络模型&#xff09; 文章传送MNIST数据集介绍&#xff1a;实验过程实验环境导入模块导入MNIST数据集创建神经网络模型进行训练&#xff0c;测试&#xff0c;评估模型优化 文章传送 机器学习之监督学习&#…

Qt绘制动态仪表(模仿汽车仪表指针、故障灯)

背景&#xff1a; 项目需要&#xff0c;可能需要做一些仪表显示。此篇除了介绍实现方法&#xff0c;还要说明心路历程。对我而言&#xff0c;重要的是心理&#xff0c;而不是技术。写下来也是自勉。 本人起初心里是比较抵触的&#xff0c;从业20多年了&#xff0c;深知所谓界…

springboot Web基础开发

Spring Boot 是一个用于简化 Spring 应用开发的框架&#xff0c;它通过自动配置和开箱即用的功能&#xff0c;使得创建和部署 Spring 应用变得更为高效。以下是 Spring Boot 基础 Web 开发的一些关键点和实操总结&#xff1a; 1. 项目搭建 使用 Spring Initializr: 访问 Spring…

【Centos】关于容器启动Centos7缺失字符集的问题

最近做一些软件测试和打包&#xff0c;需要频繁的装系统&#xff0c;索性用docker启Centos容器来做&#xff0c;基础镜像做好直接启就好&#xff0c;过程中遇到一个和字符集有关的问题&#xff0c;记录一下&#xff0c;方便遇到同样问题的小伙伴。 问题描述 运行某些python脚本…

Stable Diffusion绘画 | ControlNet应用-Inpaint(局部重绘):更完美的重绘

Inpaint(局部重绘) 相当于小号的AI版PS&#xff0c;不但可以进行局部画面的修改&#xff0c;还可以去除背景中多余的内容&#xff0c;或者是四周画面内容的扩充。 预处理器说明 Inpaint_Global_Harmonious&#xff1a;重绘-全局融合算法&#xff0c;会对整个图片的画面和色调…

达梦CASE_SENSITIVE参数解析

1. 参数含义 标识符大小写敏感&#xff0c;默认值为 Y。 当大小写敏感时&#xff0c;小写的标识符应用双引号括起&#xff0c;否则被转换为大写&#xff1b;当大小写不敏感时&#xff0c;系统不自动转换标识符的大小写&#xff0c;在标识符比较时也不区分大小写。 CASE_SENS…

QtCreator学习(二).在stm32mp1中使用

0.配置编译环境 复制【正点原子】STM32MP157开发板&#xff08;A盘&#xff09;-基础资料\05、开发工具\01、交叉编译器st-example-image-qtwayland-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1-snapshot.sh到虚拟机chmod添加可执行文件&#xff0c;./st*运行&#xff…

【JAVA】Tomcat性能优化、安全配置、资源控制以及运行模式超详细

文章目录 一、Tomcat性能优化application.yml配置maxThreads 连接数限制压缩传输AJP禁用 二、JVM方向优化设置并行垃圾回收器查看gc日志文件 三、Tomcat安全配置入侵防范禁用非法HTTP请求方法禁止目录列出防止恶意关闭服务配置HTTPS加密协议HttpOnly标记安全头配置 四、Tomcat资…