前端WebSocket实战:别再只会用HTTP了

前端WebSocket实战:别再只会用HTTP了

前端WebSocket实战:别再只会用HTTP了

毒舌时刻

这代码写得跟网红滤镜似的——仅供参考。

各位前端同行,咱们今天聊聊前端WebSocket。别告诉我你还在用轮询获取实时数据,那感觉就像每隔一分钟就去敲门问"好了没"——烦人又低效。

为什么你需要WebSocket

最近看到一个项目,实时聊天功能用轮询实现,每秒请求一次服务器,我差点当场去世。我就想问:你是在做实时通信还是在做DDoS攻击?

反面教材

// 反面教材:轮询获取数据 function startPolling() { setInterval(async () => { const response = await fetch('/api/messages'); const messages = await response.json(); updateMessages(messages); }, 1000); // 每秒请求一次 } // 服务器:求放过 // 带宽:我扛不住了 

毒舌点评:这代码,我看了都替你的服务器着急。每秒轮询一次,你是想让服务器变成蜜蜂吗?

前端WebSocket的正确姿势

1. 基础WebSocket使用

// 正确姿势:基础WebSocket class WebSocketClient { constructor(url) { this.url = url; this.ws = null; this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; this.listeners = new Map(); } connect() { this.ws = new WebSocket(this.url); this.ws.onopen = () => { console.log('WebSocket连接成功'); this.reconnectAttempts = 0; this.emit('open'); }; this.ws.onmessage = (event) => { const data = JSON.parse(event.data); this.emit(data.type, data.payload); }; this.ws.onclose = () => { console.log('WebSocket连接关闭'); this.emit('close'); this.reconnect(); }; this.ws.onerror = (error) => { console.error('WebSocket错误:', error); this.emit('error', error); }; } send(type, payload) { if (this.ws && this.ws.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify({ type, payload })); } } on(event, callback) { if (!this.listeners.has(event)) { this.listeners.set(event, []); } this.listeners.get(event).push(callback); } emit(event, data) { if (this.listeners.has(event)) { this.listeners.get(event).forEach(callback => callback(data)); } } reconnect() { if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; console.log(`尝试重连... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`); setTimeout(() => this.connect(), 3000); } } disconnect() { if (this.ws) { this.ws.close(); } } } // 使用 const ws = new WebSocketClient('wss://api.example.com/ws'); ws.on('open', () => { console.log('连接成功'); }); ws.on('message', (data) => { console.log('收到消息:', data); }); ws.connect(); 

2. React中使用WebSocket

// 正确姿势:React中使用WebSocket import { useEffect, useRef, useState, useCallback } from 'react'; function useWebSocket(url) { const [isConnected, setIsConnected] = useState(false); const [messages, setMessages] = useState([]); const ws = useRef(null); useEffect(() => { ws.current = new WebSocket(url); ws.current.onopen = () => setIsConnected(true); ws.current.onclose = () => setIsConnected(false); ws.current.onmessage = (event) => { const data = JSON.parse(event.data); setMessages(prev => [...prev, data]); }; return () => { ws.current.close(); }; }, [url]); const sendMessage = useCallback((message) => { if (ws.current && ws.current.readyState === WebSocket.OPEN) { ws.current.send(JSON.stringify(message)); } }, []); return { isConnected, messages, sendMessage }; } // 使用 function ChatRoom() { const { isConnected, messages, sendMessage } = useWebSocket('wss://chat.example.com'); const [input, setInput] = useState(''); const handleSend = () => { sendMessage({ type: 'chat', content: input }); setInput(''); }; return ( <div> <div>状态: {isConnected ? '已连接' : '未连接'}</div> <div className="messages"> {messages.map((msg, i) => ( <div key={i}>{msg.content}</div> ))} </div> <input value={input} onChange={e => setInput(e.target.value)} /> <button onClick={handleSend}>发送</button> </div> ); } 

3. 使用Socket.io

// 正确姿势:使用Socket.io import { io } from 'socket.io-client'; const socket = io('https://api.example.com', { transports: ['websocket'], autoConnect: true, reconnection: true, reconnectionAttempts: 5, reconnectionDelay: 3000 }); // 连接事件 socket.on('connect', () => { console.log('连接成功, ID:', socket.id); }); // 断开连接 socket.on('disconnect', () => { console.log('连接断开'); }); // 监听消息 socket.on('message', (data) => { console.log('收到消息:', data); }); // 发送消息 socket.emit('chat message', { text: 'Hello' }); // 加入房间 socket.emit('join room', 'room-1'); // 离开房间 socket.emit('leave room', 'room-1'); 

毒舌点评:早这么写,你的实时通信早做好了。别告诉我你还在用轮询,那你还是趁早去用短信吧。

实战技巧:WebSocket指南

1. WebSocket使用场景

  • 实时聊天:即时通讯
  • 实时数据:股票、比分
  • 协同编辑:多人协作
  • 在线游戏:实时对战

2. 最佳实践

  1. 重连机制:断线自动重连
  2. 心跳检测:保持连接活跃
  3. 消息确认:确保消息送达
  4. 错误处理:优雅处理异常

最后想说的

WebSocket不是新技术,是实时通信的标准。别再只会用HTTP了——WebSocket一下,你的应用会实时起来。

WebSocket就像电话,HTTP就像写信。紧急的事打电话,不急的事写信。别什么事都写信,学会打电话。

Read more

基于深度学习的无人机航拍小目标检测算法研究

基于深度学习的无人机航拍小目标检测算法研究

本项目针对无人机航拍场景下的小目标检测问题,基于 YOLO11 系列模型,在 VisDrone 2019 数据集上进行训练与优化,并提供了完整的检测系统桌面应用,支持图片、视频、摄像头的实时检测与训练指标可视化。 一、项目概述 无人机航拍图像具有目标尺度小、密集分布、多尺度混合等特点,传统检测算法难以取得理想效果。本项目采用 Ultralytics YOLO11 框架,结合 VisDrone 数据集进行训练,实现了对行人、车辆等 10 类交通相关目标的高效检测,并配套开发了基于 PyQt6 的桌面应用,便于模型验证与日常使用。 二、数据集 2.1 数据集简介 本项目使用 VisDrone 2019-DET 数据集,由天津大学机器学习与数据挖掘实验室 AISKYEYE 团队发布,对应 ICCV 2019 "Vision

机器人自主导航避障全栈方案(涵盖ROS2实现与实车测试数据)

第一章:机器人自主导航避障全栈方案概述 实现机器人在复杂环境中的自主导航与动态避障,依赖于一套完整的软硬件协同系统。该方案涵盖感知、定位、路径规划与运动控制四大核心模块,结合传感器融合、SLAM算法与实时控制系统,构建高效可靠的自主移动能力。 核心功能模块 * 环境感知:通过激光雷达(LiDAR)、深度相机和超声波传感器采集周围障碍物信息 * 定位与建图:利用SLAM技术实现实时地图构建与机器人自身位姿估计 * 路径规划:结合全局A*或Dijkstra算法与局部动态窗口法(DWA)进行轨迹生成 * 运动控制:基于PID或MPC控制器驱动电机执行规划路径 典型技术栈构成 层级技术组件说明硬件层Raspberry Pi + STM32 + LiDAR主控与传感单元组合中间件ROS 2 (Humble)提供节点通信与驱动支持算法层Cartographer + DWA Planner实现建图与避障决策 基础启动指令示例 # 启动ROS2导航堆栈(Nav2) ros2 launch nav2_bringup bringup_launch.py \ map:=/map

CFAR 目标检测算法详解(附 MATLAB 示例)

CFAR 目标检测算法详解(附 MATLAB 示例)

CFAR 目标检测算法,毫米波雷达工程师必须掌握的第一种检测算法 一、为什么雷达需要“目标检测算法”? 在毫米波雷达中,我们最终想知道的不是“信号长什么样”,而是: 哪里有目标?目标有多少?哪些是噪声? 然而,雷达接收到的信号永远是下面三者的混合: 1. 真实目标回波 2. 环境杂波(地面、墙面、人体、车辆反射) 3. 系统噪声(热噪声、量化噪声等) 在经过 ADC → FFT → 距离谱 / 多普勒谱 后,你会看到大量起伏的谱线。 问题来了: 在一个噪声水平不断变化的环境中,如何“公平、稳定”地判断某个峰值是不是目标? 这正是 CFAR(Constant False Alarm Rate,恒虚警率)算法存在的意义。 二、CFAR

基于FPGA的毕业设计题目效率提升指南:从串行仿真到并行硬件加速的实战演进

作为一名刚刚完成FPGA毕业设计的过来人,我深刻体会过那种被漫长仿真和反复调试支配的恐惧。一个简单的改动,动辄需要数小时的仿真验证,再加上烧录、测试,一天时间可能就没了。今天,我想结合自己的实战经验,和大家聊聊如何系统性地提升基于FPGA的毕业设计效率,核心思路就是从“串行思维”转向“并行硬件思维”。 1. 效率瓶颈诊断:你的时间都去哪儿了? 在开始优化之前,我们先得搞清楚效率低下的症结所在。根据我和身边同学的经验,瓶颈主要集中在以下几个方面: 1. 漫长的仿真周期:这是最大的时间杀手。用ModelSim或Vivado Simulator跑一个稍复杂的算法(比如图像处理),仿真几分钟甚至几十分钟是常事。每次修改代码后都要经历这个漫长的等待,严重拖慢迭代速度。 2. 反复的烧录与板级调试:仿真通过后,上板测试又是另一道坎。频繁的烧录操作本身耗时,更重要的是,硬件行为与仿真不一致时,定位问题极其困难,缺乏有效的调试手段。 3. 逻辑资源利用低效与碎片化:手动编写Verilog时,容易陷入“能跑就行”的思维,没有充分考虑硬件并行性。导致设计占用大量查找表(LUT)和触发器(FF)