这是我参与更文挑战的第2天,活动详情查看: 更文挑战
使用了Remax很长的时间,之前使用javascript版本
在六月份项目准备使用Typescript重构,故重新思考整理一个版本
小小知识点
微信小程序的wx.connectSocket只能同时对一个ws/wss的websocket发起最多两次请求,对于多个不同的websocket地址可以使用最多5个连接。
微信SocketTask是先使用connectSocket建立连接后可以返回一个SocketTask的对象。可以将这个连接存储在当前内部。但是不推荐,因为当页面刷新后websocket的连接很可能会丢失。而使用本地的localstroage进行缓存是拿不到的socket.
所以建议,每次使用新的websocket连接的时候实例化一次。再传入相应的ws/wss连接进行链接操作。
Websocket的调用是有时序的
( 连接 – 判断是否已打开 – 接收服务器的参数 – 发送给服务器信息 )
wx.connectSocket -> wx.onSocketOpen -> wx.onReceivedMsg -> wx.sendSocketMessage
所以当遇到无法发送或者接收服务器和推送数据到服务器的时候,应该检查一下执行时序的问题。
filename: src/utils/websocket.ts
import {
connectSocket,
closeSocket,
onSocketOpen,
onSocketClose,
sendSocketMessage,
onSocketMessage,
getNetworkType,
onNetworkStatusChange,
} from 'remax/wechat';
class Websocket {
// 是否连接
isConnect: boolean = false;
// 当前网络状态
private netWork: boolean = false;
// 是否人为退出
private isClosed: boolean = false;
// 心跳检测频率
private timeout: number = 3 * 1000;
private timeoutObj: NodeJS.Timeout | undefined;
// 当前重连次数
private connectNum: number = 0;
// 心跳检测和断线重连开关,true为启用,false为关闭
heartCheck: boolean = false
isReconnect: boolean = false
// 连接信息
wsUrl = ''
// 消息队列
messageQueue = []
constructor(heartCheck: boolean = false, isReconnect: boolean = false) {
// 心跳检测和断线重连开关,true为启用,false为关闭
this.heartCheck = heartCheck;
this.isReconnect = isReconnect;
}
// 心跳开始
start() {
const self = this;
this.timeoutObj = setInterval(() => {
sendSocketMessage({
// 发送心跳信息
data: JSON.stringify({
beat: 'dj',
}),
success() {
// console.log("发送心跳成功");
},
fail(err) {
console.log(err);
console.log('连接失败');
self.reConnect()
self.reset();
},
}).then();
}, this.timeout);
}
// 心跳重置
reset() {
if (this.timeoutObj) {
clearTimeout(this.timeoutObj);
}
// 返回this即可支持链式调用
return this;
}
// 初始化连接
init(wsUrl: string) {
if (this.isConnect) {
this.onSocketOpened()
this.onNetworkChange()
this.onSocketClosed()
} else {
// 检查网络状态
const self = this;
getNetworkType({
success(res) {
if (res.networkType !== 'none') {
// 开始建立连接
console.log('开始连接')
self.connect(wsUrl)
} else {
self.netWork = false;
console.log('网络已断开');
}
},
}).then();
}
}
// 连接websocket
connect(wsUrl: string) {
// connectSocket不支持异步调用
let self = this;
connectSocket({
url: wsUrl,
success(res) {
if (res.errMsg == 'connectSocket:ok') {
self.isConnect = true
self.wsUrl = wsUrl
self.onSocketOpened()
self.onNetworkChange()
self.onSocketClosed()
}
},
fail(err) {
console.log(err)
},
});
}
// 重连方法,会根据时间频率越来越慢,分别为3秒,10秒,45秒
reConnect() {
console.log(this.connectNum)
if (!this.isConnect) {
if (this.connectNum < 3) {
setTimeout(() => {
this.init(this.wsUrl);
}, 3 * 1000);
this.connectNum += 1;
} else if (this.connectNum < 10) {
setTimeout(() => {
this.init(this.wsUrl);
}, 10 * 1000);
this.connectNum += 1;
} else {
setTimeout(() => {
this.init(this.wsUrl);
}, 45 * 1000);
this.connectNum += 1;
}
}
}
// 关闭websocket连接
close() {
if (this.isConnect) {
closeSocket().then()
// 重置心跳并改变相应状态
this.reset()
this.isClosed = true;
this.isConnect = false;
} else {
console.warn('没有websocket连接')
}
}
// 监听websocket连接关闭
onSocketClosed() {
onSocketClose((err) => {
console.log(`当前websocket连接已关闭,错误信息为:${JSON.stringify(err)}`);
// 停止心跳连接
if (this.heartCheck) {
this.reset();
}
// 关闭已登录开关
this.isConnect = false;
// 检测是否是用户自己退出小程序
if (!this.isClosed) {
console.log('进来了这里...')
// 进行重连
if (this.isReconnect) {
this.reConnect();
}
}
});
}
// 检测网络变化
onNetworkChange() {
let self = this;
onNetworkStatusChange((res) => {
if (res.isConnected) {
self.isConnect = false;
self.reConnect()
}
});
}
// socket已开启
onSocketOpened() {
onSocketOpen(() => {
console.log('websocket已打开');
// 打开已连接开关
this.isConnect = true;
this.netWork = true;
// 发送心跳
if (this.heartCheck) {
this.reset().start();
}
});
}
// 接收服务器返回的消息
onReceivedMsg(callBack: any) {
onSocketMessage((msg) => {
if (typeof callBack === 'function') {
callBack(msg);
}
});
}
// 发送ws消息
sendWebSocketMsg(options: any) {
sendSocketMessage({
data: options.data,
success(res) {
if (options.success && typeof options.success === 'function') {
options.success(res);
}
},
fail(err) {
if (options.fail && typeof options.fail === 'function') {
options.fail(err);
}
},
}).then();
}
}
const websocket = new Websocket(
// true代表启用心跳检测和断线重连
true,
true,
);
export default websocket;
复制代码
如何使用呢?
filename: src/page/index.tsx
import * as React from 'react';
import {View, Text, Image, Button} from 'remax/wechat';
import styles from './index.css';
import websocket from "@/utils/wxsocket";
export default () => {
const connectWs = () => {
const wsUrl = `ws://测试或者线上的ws地址信息如果是https加密则使用wss://`
if (!websocket.isConnect) {
websocket.init(wsUrl)
}
}
const closeWs = () => {
if (websocket.isConnect) {
websocket.close()
}
}
return (
<View className={styles.app}>
<View className={styles.header}>
<Image
src="https://gw.alipayobjects.com/mdn/rms_b5fcc5/afts/img/A*OGyZSI087zkAAAAAAAAAAABkARQnAQ"
className={styles.logo}
/>
<Button onClick={() => connectWs()}>开始连接ws服务器</Button>
<Button onClick={() => closeWs()}>关闭ws连接服务器</Button>
</View>
</View>
);
};
复制代码
连接上后
关闭链接后
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END