Files
cashier-ipad-new/http/websock.js
2025-12-25 19:03:44 +08:00

325 lines
9.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// WebSocket 工具类 - 优化版
class WebsocketUtil {
constructor(url, time, params) {
this.url = url;
this.params = params;
this.time = time;
this.socketTask = null;
this.isOpen = false;
this.isAppActive = true; // 应用是否活跃(前台)
// 定时器相关
this.reconnectTimeout = null;
this.heartbeatInterval = null;
this.heartbeatTimeout = null;
this.checkConnectionInterval = null;
// 消息回调数组
this.messageCallbacks = [];
// 重连策略配置
this.reconnectAttempts = 0;
this.reconnectMaxAttempts = 5;
this.reconnectDelay = 3000;
this.maxReconnectDelay = 30000;
// 事件监听器引用(用于销毁时移除)
this.appShowListener = null;
this.appHideListener = null;
this.networkListener = null;
this.visibilityChangeListener = null;
// 初始化事件监听
this.initEventListeners();
// 初始化 WebSocket 连接
this.initializeWebSocket();
}
// 初始化全局事件监听
initEventListeners() {
// 1. 监听应用显示/隐藏Uniapp 全局事件)
this.appShowListener = uni.onAppShow(() => {
console.log('应用从后台回到前台');
this.isAppActive = true;
// 重置重连状态,立即尝试重连
this.resetReconnectState();
this.checkConnection();
this.startHeartbeat();
this.startConnectionCheck();
});
this.appHideListener = uni.onAppHide(() => {
console.log('应用进入后台');
this.isAppActive = false;
// 后台时暂停心跳和连接检查,避免无效重连
this.pauseHeartbeat();
this.pauseConnectionCheck();
});
// 2. 监听网络状态变化
this.networkListener = uni.onNetworkStatusChange((res) => {
console.log('网络状态变化:', res);
if (res.isConnected) {
// 网络恢复,重置重连状态并立即重连
this.resetReconnectState();
this.checkConnection();
}
});
// 3. 监听页面可见性变化Web 端兼容)
if (typeof document !== 'undefined') {
this.visibilityChangeListener = () => {
if (document.visibilityState === 'visible') {
console.log('页面可见,激活连接');
this.isAppActive = true;
this.resetReconnectState();
this.checkConnection();
this.startHeartbeat();
this.startConnectionCheck();
} else {
console.log('页面隐藏,暂停连接活动');
this.isAppActive = false;
this.pauseHeartbeat();
this.pauseConnectionCheck();
}
};
document.addEventListener('visibilitychange', this.visibilityChangeListener);
}
}
// 重置重连状态(用于应用前台切换、网络恢复时)
resetReconnectState() {
this.reconnectAttempts = 0;
this.reconnectDelay = 3000;
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
this.reconnectTimeout = null;
}
}
// 初始化 WebSocket 连接
initializeWebSocket() {
console.log('初始化WebSocket连接');
if (this.isOpen) return;
// 关闭之前可能存在的连接
if (this.socketTask) {
this.closeSocket();
}
this.socketTask = uni.connectSocket({
url: this.url,
success: () => {
console.log('WebSocket连接请求发送成功');
},
fail: (error) => {
console.error('WebSocket连接失败:', error);
uni.$emit('is-socket-open', false);
this.reconnect();
}
});
// 连接打开事件
this.socketTask.onOpen((res) => {
console.log('WebSocket连接正常', res);
this.isOpen = true;
this.resetReconnectState(); // 重置重连状态
this.startHeartbeat();
this.listenForMessages();
uni.$emit('is-socket-open', true);
});
// 连接错误事件
this.socketTask.onError((res) => {
console.error('WebSocket连接错误:', res);
uni.$emit('is-socket-open', false);
this.reconnect();
});
// 连接关闭事件
this.socketTask.onClose((result) => {
console.log('WebSocket连接已关闭:', result);
this.isOpen = false;
// 只有应用活跃时才重连
if (this.isAppActive) {
this.reconnect();
}
});
// 启动连接状态主动检查
this.startConnectionCheck();
}
// 启动心跳检测(仅在应用活跃时)
startHeartbeat() {
if (!this.isAppActive) return;
// 清除现有定时器
this.pauseHeartbeat();
this.heartbeatInterval = setInterval(() => {
if (this.isOpen && this.isAppActive) {
// 发送心跳包
this.send(JSON.stringify({ "type": "ping_interval", "set": "pad" }));
// 5秒超时检测
this.heartbeatTimeout = setTimeout(() => {
console.log('心跳超时,主动断开并重连');
this.closeSocket();
this.reconnect();
}, 5000);
}
}, this.time);
}
// 暂停心跳检测
pauseHeartbeat() {
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
this.heartbeatInterval = null;
}
if (this.heartbeatTimeout) {
clearTimeout(this.heartbeatTimeout);
this.heartbeatTimeout = null;
}
}
// 启动连接状态主动检查30秒一次
startConnectionCheck() {
if (this.checkConnectionInterval) clearInterval(this.checkConnectionInterval);
this.checkConnectionInterval = setInterval(() => {
this.checkConnection();
}, 30000);
}
// 暂停连接状态检查
pauseConnectionCheck() {
if (this.checkConnectionInterval) {
clearInterval(this.checkConnectionInterval);
this.checkConnectionInterval = null;
}
}
// 主动检查连接状态
checkConnection() {
if (this.isAppActive && !this.isOpen && !this.reconnectTimeout) {
console.log('主动检查到连接断开,触发重连');
this.reconnect();
}
}
// 发送消息
send(data, type) {
if (this.socketTask && this.isOpen) {
this.socketTask.send({
data: data,
success: () => {
this.startHeartbeat(); // 发送成功重置心跳
},
fail: (error) => {
console.error('消息发送失败:', error);
this.reconnect();
}
});
} else {
console.warn('WebSocket未连接无法发送消息');
}
}
// 监听 WebSocket 消息
listenForMessages() {
if (this.socketTask) {
this.socketTask.onMessage((res) => {
const data = res.data.toString();
try {
const message = JSON.parse(data);
if (message.type === 'pong') {
// 收到pong清除心跳超时
if (this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout);
}
} catch (e) {
console.warn('消息解析失败非JSON格式:', e);
}
// 触发外部回调
this.messageCallbacks.forEach(callback => callback(data));
});
}
}
// 重连 WebSocket指数退避 + 应用活跃检测)
reconnect() {
// 应用在后台时,延迟重连
if (!this.isAppActive) {
console.log('应用在后台,延迟重连');
return;
}
if (this.reconnectTimeout) clearTimeout(this.reconnectTimeout);
// 达到最大重连次数,停止重试
if (this.reconnectAttempts >= this.reconnectMaxAttempts) {
console.log(`已达最大重连次数 ${this.reconnectMaxAttempts},停止重连`);
return;
}
// 指数退避延迟
const delay = Math.min(
this.reconnectDelay * Math.pow(2, this.reconnectAttempts),
this.maxReconnectDelay
);
this.reconnectTimeout = setTimeout(() => {
this.reconnectAttempts++;
console.log(`重连尝试 ${this.reconnectAttempts}/${this.reconnectMaxAttempts},延迟 ${delay}ms`);
this.initializeWebSocket();
}, delay);
}
// 关闭 WebSocket 连接
closeSocket() {
if (this.socketTask) {
uni.closeSocket({
success: () => {
console.log('WebSocket连接已关闭');
this.isOpen = false;
},
fail: (error) => {
console.error('关闭WebSocket连接失败:', error);
}
});
this.socketTask = null;
}
}
// 外部注册消息回调
onMessage(callback) {
this.messageCallbacks.push(callback);
}
// 外部注销消息回调
offMessage(callback) {
this.messageCallbacks = callback
? this.messageCallbacks.filter(cb => cb !== callback)
: [];
}
// 销毁 WebSocket 连接,清理资源
destroy() {
this.closeSocket();
// 清除所有定时器
this.pauseHeartbeat();
this.pauseConnectionCheck();
clearTimeout(this.reconnectTimeout);
// 移除所有事件监听
if (this.appShowListener) uni.offAppShow(this.appShowListener);
if (this.appHideListener) uni.offAppHide(this.appHideListener);
if (this.networkListener) uni.offNetworkStatusChange(this.networkListener);
if (this.visibilityChangeListener && typeof document !== 'undefined') {
document.removeEventListener('visibilitychange', this.visibilityChangeListener);
}
// 清空回调数组
this.messageCallbacks = [];
console.log('WebSocket资源已销毁');
}
}
export default WebsocketUtil;