前端面试练习24.3.6

2024-03-07 18:04

本文主要是介绍前端面试练习24.3.6,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:

今天就是复习回顾一下websocket,之前有个AI项目使用到了这个,有点久远了,回顾一下大致过程和难点。

一些知识点:

1.单工,半双工,全双工

单工:

数据只能沿着一个方向传递,例如电视广播等。

优点:实现简单

缺点:传输效率低

半双工:

数据可以在双方之间进行传递,但是不能同时进行,必须有个 发送/接收 角色的转换,一方发送完成另一方才能发送。比如对讲机。

全双工:

数据可以同时在两个方向上传输,通信的两个设备之间可以同时的收发消息,无需等待对方完成,极大地提高了数据的传输效率,典型用例就是电话。

2.websocket可能遇到的难点

参考WebSocket项目中难点与解决方法_websocket客服聊天 难点-CSDN博客

难点一:连接的建立与保持

1.采用连接池

WebSocket初始连接负担较大,主要体现在频繁的连接建立和保持连接的开销较高。

采用连接池,服务端解决

引入了websocket-pool库,通过维护连接池,成功实现了连接的复用。这极大地降低了频繁建立和关闭连接的开销,提升了性能。

 

2.心跳机制引入

 实施了定时的心跳机制,周期性地向服务器发送心跳消息,确保连接保持活跃。这有效防止了连接被自动关闭,提高了连接的可靠性。

3.长连接,适当延长连接时常

比如在连接时,设置超时时长5秒,5秒内没有得到服务器回应,则出现超时提示​​​​​​​

  

难点二:错误处理与断线重连

1.错误处理

 监听onerror事件,当 WebSocket 发生错误时,执行回调函数捕获错误信息​​​​​​​

2.短线重连

 自动断线重连机制,采用了指数退避算法。通过逐渐增加重连的间隔时间,我们成功避免了频繁尝试重新建立连接,确保了连接的稳定性和用户体验。

难点三:性能的一些优化

1.消息压缩

目前还没解决

2.并发限制

连接池设置最大数量

3.消息队列

目前没解决

websocket实战:

服务端创建websocket服务

创建node项目,安装相关依赖

npm init -y
npm install express
npm install ws
const WebSocket = require('ws');
const PORT = 8080;
const URL = 'ws://127.0.0.1:8080';
const wss = new WebSocket.Server({ port: PORT });
const clients = new Map();wss.on('connection', function connection(ws) {console.log('Client connected');ws.on('message', function incoming(message) {const data = JSON.parse(message);if (typeof data !== 'string') {let targetUser = data.toUser// 如果客户端之前没有存储在 clients Map 中,则存储客户端连接if (!clients.has(data.user)) {clients.set(data.user, ws);}console.log(clients.keys())// 将格式化后的消息发送给客户端const formattedMessage = `${data.user}:  - ${data.time}<br>${data.message}`;if (clients.has(targetUser)) {ws.send(formattedMessage);const clientSocket = clients.get(targetUser);// 检查连接是否已经打开if (clientSocket.readyState === WebSocket.OPEN) {// 发送消息给目标用户clientSocket.send(formattedMessage);} else {clientSocket.send(`连接到用户 ${targetUser} 的WebSocket已关闭。`);}} else {ws.send(`用户 ${targetUser} 不在线或未连接到WebSocket服务器。`);}console.log('Received:', formattedMessage);}});// 当完成后释放连接回连接池// webSocketPool.releaseConnection(connection);
});console.log('WebSocket server is running on port 8080');
console.log(`WebSocket 服务器正在监听 127.0.0.1:${PORT}`);

客户端编写连接代码

<!DOCTYPE html>
<html><head><meta charset='utf-8'><title>前端学习</title><style>* {margin: 0px;padding: 0px;}</style>
</head><body>写一个聊天显示的窗口,以及信息发送输入框和发送按钮<div id='chat' style="display: flex;justify-content: space-around;"><div class="box1"><div id='user1_messages' style="width: 600px;height: 300px;border:1px solid black"><h1>WebSocket1 user:<span id="user1_h1" style="color: rgb(232, 154, 66);"></span></h1></div><input type='text' id='messageInput1' autocomplete='off' placeholder='Type your message here...'><button id='sendButton1'>Send</button></div><div class="box2"><div id='user2_messages' style="width: 600px;height: 300px;border:1px solid black"><h1>WebSocket2 user:<span id="user2_h1" style="color: rgb(232, 154, 66);"></span></h1></div><input type='text' id='messageInput2' autocomplete='off' placeholder='Type your message here...'><button id='sendButton2'>Send</button></div></div><script type='text/javascript'>let data = [{user: 'xhc',message: '',time: '',toUser: ''}, {user: 'slj',message: '',time: '',toUser: ''},{user: 'aaa',message: '',time: '',toUser: ''}]let mess1 = document.getElementById('user1_messages');let mess2 = document.getElementById('user2_messages');let user1_h1 = document.getElementById('user1_h1');user1_h1.innerHTML = `${data[0].user}`let input1 = document.getElementById('messageInput1');let input2 = document.getElementById('messageInput2');let user2_h1 = document.getElementById('user2_h1');user2_h1.innerHTML = `${data[1].user}`let send1 = document.getElementById('sendButton1');let send2 = document.getElementById('sendButton2');const URL = 'ws://localhost:8080'const connect1 = () => {// 创建 WebSocket 连接const socket = new WebSocket(URL);let timer; // Variable to store the interval// 当连接打开时执行的操作socket.onopen = function (event) {console.log('WebSocket1 连接已建立');data[0].message = input1.value;data[0].time = new Date().toLocaleString();data[0].toUser = 'slj';// 发送消息到服务器socket.send(JSON.stringify(data[0]));input1.value = '';// 设置定时器,每隔30秒执行一次指定的回调函数timer = setInterval(() => {// 检查 WebSocket 连接的当前状态是否为 OPENif (socket.readyState === WebSocket.OPEN) {// 如果连接处于 OPEN 状态,则通过连接对象发送心跳消息 'keep-alive'socket.send(JSON.parse('keep-alive'));}}, 30000); // 每 30 秒发送一次心跳};// 当接收到消息时执行的操作socket.onmessage = function (event) {let reply = event.data;mess1.innerHTML = `${mess1.innerHTML} <br>${reply}`;console.log('来自服务器的消息1:', reply);};// 当连接关闭时执行的操作socket.onclose = function (event) {mess1.innerHTML = 'WebSocket1 连接已关闭';console.log('WebSocket1 连接已关闭');// 清除定时器clearInterval(timer);};};send1.addEventListener('click', connect1)let reconnectDelay = 2000; // 初始重连延迟为 2 秒let reconnectCount = 0; // 当前重连次数const maxReconnectCount = 7; // 最大重连次数为 7const maxReconnectDelay = 60000; // 最大重连延迟为 60 秒const connect2 = () => {let socket; // WebSocket 连接对象let timer; // 用于心跳的定时器let timeoutTimer; // 连接超时的定时器// 定义超时操作函数function handleTimeout() {console.error('WebSocket2 连接超时');// 关闭连接if (socket) {socket.close();}}// 定义重新连接函数function reconnect() {reconnectCount++;console.log(`尝试重新连接 WebSocket2,第 ${reconnectCount} 次...`);clearTimeout(timeoutTimer); // 清除超时计时器if (reconnectCount <= maxReconnectCount) {setTimeout(connect2, reconnectDelay); // 重新连接// 更新重连延迟时间,采用指数退避算法reconnectDelay = Math.min(2 * reconnectDelay, maxReconnectDelay);} else {console.error(`WebSocket2 重连失败,已达到最大重连次数 (${maxReconnectCount} 次)`);}}// 创建 WebSocket 连接socket = new WebSocket(URL);// 当连接打开时执行的操作socket.onopen = function (event) {console.log('WebSocket2 连接已建立');data[1].message = input2.value;data[1].time = new Date().toLocaleString();data[1].toUser = 'xhc';// 发送消息到服务器if (socket.readyState === WebSocket.OPEN) {// 如果连接处于 OPEN 状态,则通过连接对象发送消息socket.send(JSON.stringify(data[1]));} else {console.log('WebSocket2 连接未建立/连接建立失败/连接关闭');}input2.value = '';// 设置定时器,每隔30秒执行一次指定的回调函数timer = setInterval(() => {// 检查 WebSocket 连接的当前状态是否为 OPENif (socket.readyState === WebSocket.OPEN) {// 如果连接处于 OPEN 状态,则通过连接对象发送心跳消息 'keep-alive'socket.send(JSON.parse('keep-alive'));}}, 30000); // 每 30 秒发送一次心跳// 设置超时计时器timeoutTimer = setTimeout(handleTimeout, reconnectDelay);};// 当接收到消息时执行的操作socket.onmessage = function (event) {mess2.innerHTML = `${mess2.innerHTML} <br>${event.data}`;console.log('来自服务器的消息2:', event.data);// 清除超时计时器clearTimeout(timeoutTimer);};// 当连接关闭时执行的操作socket.onclose = function (event) {mess2.innerHTML = 'WebSocket2 连接已关闭';console.log('WebSocket2 连接已关闭');// 清除定时器if (timer) {clearInterval(timer);}};// 当发生错误时执行的操作socket.onerror = function (error) {console.error('WebSocket2 连接发生错误:', error);// 清除超时计时器clearTimeout(timeoutTimer);clearInterval(timer);};};send2.addEventListener('click', connect2)</script>
</body></html>

这篇关于前端面试练习24.3.6的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/784359

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

RabbitMQ练习(AMQP 0-9-1 Overview)

1、What is AMQP 0-9-1 AMQP 0-9-1(高级消息队列协议)是一种网络协议,它允许遵从该协议的客户端(Publisher或者Consumer)应用程序与遵从该协议的消息中间件代理(Broker,如RabbitMQ)进行通信。 AMQP 0-9-1模型的核心概念包括消息发布者(producers/publisher)、消息(messages)、交换机(exchanges)、

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo