多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
### 前言 传统http短连接拉取接收数据太浪费资源,tcp每次都得建立连接,三次握手,释放,只能单向通信,定时轮询。 而websocket可以建立长连接,后一直保持,节约服务器资源,跟每台客户机只维持一个连接就行。 节省流量 不需要频繁地发起关闭tcp连接,可以双向通信, 协议以及数据格式自己算了算,浏览器、app、物联网多种设备一套接口通用,省略HTTP上不多余的信息, 基于以上原因,开发一套socket框架来代替http ajax模式,同时保持跟http一样容易上手 ### 目的 用websocket实现Ajax回调效果,所有接口请求用websocket进行, 想要使websocket发送的消息实现跟ajax回调消息那种效果,发送出去,然后回调函数里收到服务器发送来的消息 ### 难点 websocket与http不同的之处在于,http发的请求是同步的,浏览器发起请求会同步等待服务器返回,而socket是发送完了就结束了,不管服务器又没返回,而且先发地数据不一定先收到,不按顺序返回, 难点就在于发送数据在ws.send函数里,而接收数据在ws.onmessage里,数据不能互通 ### 原理 解决方法 发送消息的时候把回调函数存到一个数组中,数组下标用唯一键名避免冲突,键名要发送给服务器,服务器返回数据的时候要带上, 收到服务器消息时,取出键名去调用数组中对应的回调函数,把数据传入回调函数执行回调操作 这样就实现了跟ajax一样的效果 ### 实现 代码示例 socket.js ` //websocket地址 let host = "ws://localhost:8282"; let ws = null; let socketOpen = false; let callbackArr = []; let msgArr = []; //心跳时间 let heartCheckTime = 45000; //重连尝试次数 let reconnectTime = 0; function wsConnect() { ws = new WebSocket(host); // 打开socket连接 ws.onopen = e => { socketOpen = true; console.log('连接成功'); //待发送消息队列 if (msgArr.length) { for (let i in msgArr) { sendMsg(msgArr[i].data, msgArr[i].callback) } msgArr = [] } // 心跳 heartCheck() }; // socketClose ws.onclose = e => { console.log('连接已断开', e); socketOpen = false; reconnect(); }; //连接发生错误 ws.onerror = e => { console.log('连接发生错误', e); socketOpen = true; reconnect(); }; //接收消息 ws.onmessage = e => { // 按api保存回调 let callBackData = JSON.parse(e.data); let key = callBackData.key; if (!key) return; callbackArr[key](callBackData) } } // 发送消息 function send(data, callback) { callbackArr[data.key] = callback // console.log('发送消息',data) if (socketOpen) { ws.send(JSON.stringify(data)) } else { // 未开启,加入队列 msgArr.push({data, callback}); wsConnect(); } } // 心跳检测 function heartCheck() { if (socketOpen) { setInterval(() => { ws.send('ping') console.log("发送ping", heartCheckTime) }, heartCheckTime); } } // 重连 function reconnect() { if (!socketOpen && reconnectTime <= 10) { setTimeout(() => { wsConnect() reconnectTime++ console.log('重新连接', reconnectTime) }, 2000) } } module.exports.send = send `