網站首頁 編程語言 正文
interface Class2Type {
[key: string]: string;
}
export function _typeof(value: any) {
const class2type: Class2Type = {};
"Boolean Number String Function Array Date RegExp Object Error".split(" ").forEach((key) => {
class2type["[object " + key + "]"] = key.toLowerCase();
});
if (value === null) return String(value);
return typeof value === "object" || typeof value === "function" ? class2type[class2type.toString.call(value)] || "object" : typeof value;
}
/**
* websocket 類
* @class
* @param {object|string} options-傳遞參數
* @param {string} options.url-websocket 連接地址
* @param {string|object[]} [options.protocol]-子協議
* @param {reconnect} [options.reconnect]-斷開后是否自動連接
* @param {number} [reconnectIntervalInMilliSeconds]-連接時間
**/
interface Options {
url: string;
reconnect?: boolean;
reconnectIntervalInMilliSeconds?: number;
}
interface Watcher {
open: any[];
message: any[];
close: any[];
error: any[];
}
type WebSocketPayload = string | ArrayBuffer | Blob
interface WebSocketLike {
close(): any;
send(data: WebSocketPayload): any;
onopen: ((event: any) => any) | null;
onclose: ((event: any) => any) | null;
onmessage: ((event: any) => any) | null;
onerror: ((event: any) => any) | null;
readyState: number;
}
const defaultOptions = {
url: "",
reconnect: true,
reconnectIntervalInMilliSeconds: 0,
};
class WebSocketClass {
private ws: WebSocketLike | null;
private reconnectTimeOut: null | number;
private readonly url: string;
private readonly reconnect: boolean;
private readonly reconnectIntervalInMilliSeconds: number;
private isDestroy: boolean;
private attempts: number;
private serverHeartTimeout: null | number;
private heartTimeout: null | number;
private heartTime: number;
private heart: boolean;
private watcher: Watcher;
private isReconnected: boolean;
constructor(options: string | Options) {
let _options = {};
if (_typeof(options) === 'string') {
_options = { url: options };
} else if (_typeof(options) === 'object' && options !== null) {
_options = options;
}
const option = Object.assign({}, defaultOptions, _options);
this.ws = new WebSocket(option.url);
this.url = option.url;
this.reconnect = option.reconnect;
this.reconnectIntervalInMilliSeconds = option.reconnectIntervalInMilliSeconds;
this.attempts = 1;
this.isDestroy = false;
this.reconnectTimeOut = null;
this.heart = false;
this.heartTime = 40000;
this.heartTimeout = null;
this.serverHeartTimeout = null;
this.isReconnected = false; // 是否在重連中
this.watcher = {
open: [],
message: [],
error: [],
close: [],
};
this._init();
}
// Websocket 開啟連接時執行
onOpen(callback: () => void) {
this.watcher['open'].push(callback);
}
// websocket 在通信中執行函數
onMessage(callback: () => void) {
this.watcher['message'].push(callback);
}
// websocket 斷開連接執行函數
onClose(callback: () => void) {
this.watcher['close'].push(callback);
}
// 銷毀當前websocket
destroy() {
this.isDestroy = true;
if (this.ws) this.ws.close();
this.ws = null;
// 清除延時
clearTimeout(this.heartTimeout!);
clearTimeout(this.serverHeartTimeout!);
clearTimeout(this.reconnectTimeOut!);
this.heartTimeout = null;
this.serverHeartTimeout = null;
this.reconnectTimeOut = null;
}
// 重連
doReconnect() {
if (this.reconnect) {
// 存在ws 則先關閉
if (this.ws) {
this.ws.close();
this.ws = null;
}
// 主動destroy,不進行重連
if (this.isDestroy) return;
// 重連判斷 在重連中則返回
if (this.isReconnected) return;
this.isReconnected = true;
const time = this._generateInterval(this.attempts);
this.reconnectTimeOut = setTimeout(() => {
this.attempts += 1;
this.isReconnected = false;
this.ws = new WebSocket(this.url);
this._init();
}, time);
}
}
// 初始化
_init() {
this.ws!.onopen = () => {
this.watcher['open'].forEach(fn => fn());
this.sendHeart();
};
this.ws!.onmessage = (event: any) => {
// 過濾心跳數據
const data = JSON.parse(event.data) || {};
if (data.c !== "r" || data.r !== "h") {
this.watcher['message'].forEach(fn => fn(data));
}
this.sendHeart();
};
this.ws!.onclose = () => {
this.watcher['close'].forEach(fn => fn());
this.doReconnect();
};
this.ws!.onerror = () => { // 默認ws報錯就執行重連 todo -- 解決第一次連接失敗
this.doReconnect();
};
}
// 監聽心跳 重連
sendHeart() {
const that = this;
clearTimeout(this.heartTimeout!);
clearTimeout(this.serverHeartTimeout!);
if (!this.isDestroy) { // ws 已經刪除不做心跳重連
this.heartTimeout = setTimeout(() => {
// 發送心跳
if (this.ws && this.ws.readyState === 1) {
this.ws.send(JSON.stringify({ 'c': 'h' }));
}
that.serverHeartTimeout = setTimeout(() => { // 如果超過一定時間還沒重置,說明后端斷開了
that.doReconnect();
}, that.heartTime);
}, that.heartTime);
}
}
// websocket 發送消息
sendMessage(message: object | string) {
const that = this;
if (message && this.ws) {
try {
this.ws.send(JSON.stringify(message));
} catch (err) {
const timer = setInterval(() => {
if (that.ws && that.ws.readyState === 1) {
that.ws.send(JSON.stringify(message));
clearInterval(timer);
}
}, 200);
const timer01 = setTimeout(() => {
clearTimeout(timer01);
clearInterval(timer);
}, 10000);
}
}
}
// 重連時間間隔控制
_generateInterval(k: number) {
if (this.reconnectIntervalInMilliSeconds > 0) {
return this.reconnectIntervalInMilliSeconds;
}
return Math.min(30, (Math.pow(2, k) - 1)) * 1000;
}
}
const websocket = (options: string | Options) => new WebSocketClass(options);
export {
websocket,
};
原文鏈接:https://blog.csdn.net/weixin_45288512/article/details/125748897
- 上一篇:css盒子模型和css邊框屬性
- 下一篇:構建npm配置包
相關推薦
- 2022-06-12 Flask項目的部署的實現步驟_python
- 2021-12-05 判斷網頁時瀏覽器打開還是釘釘打開
- 2023-01-23 React新擴展函數setState與lazyLoad及hook介紹_React
- 2022-09-18 iOS?xcconfig編寫示例教程_IOS
- 2022-07-16 BOM與DOM的進階知識
- 2022-03-31 SQL?Server的觸發器詳解_MsSql
- 2022-03-11 部署.Net6項目到docker_基礎應用
- 2022-09-25 git提交代碼版本沖突問題
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支