UNPKG

an-function

Version:

js中常用的util方法;比如处理日期的函数,a连接下载,解析url,防抖,节流,基于webWork的定时器,websocket连接等等

612 lines (588 loc) 21.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.aDownLoad = aDownLoad; exports.aDownLoad2 = aDownLoad2; exports.anWebSocket = exports.anTimeout = exports.anInterval = void 0; exports.chinaDate = chinaDate; exports.deepClone = deepClone; exports.fileToBase64 = fileToBase64; exports.getLengthArray = getLengthArray; exports.getUrlParams = getUrlParams; exports.objKeysHasValue = void 0; function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } /** * 生成一个从 1 到指定数字的数组。 * @param {number} [number=0] - 要生成的数组长度。 * @returns {number[]} 一个从 1 到 `number` 的数组。 */ function getLengthArray() { var number = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var linshi = []; for (var i = 1; i <= number; i++) { linshi.push(i); } return linshi; } /** * 创建一个对象的深拷贝。 * @param {Object} obj - 要拷贝的对象。 * @param {WeakMap} [hash=new WeakMap()] - 用于处理循环引用的 WeakMap。 * @param {boolean} [copyContructor=false] - 是否拷贝构造函数。 * @returns {Object} 对象的深拷贝。 */ function deepClone(obj) { var hash = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new WeakMap(); var copyContructor = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; // 如果浏览器支持 structuredClone,则使用它 if (typeof structuredClone === 'function') { return structuredClone(obj); } // 处理循环引用 if (hash.has(obj)) return hash.get(obj); // 处理基本类型和特殊对象 if (obj === null || _typeof(obj) !== 'object') return obj; if (obj instanceof Date) return new Date(obj); if (obj instanceof RegExp) return new RegExp(obj); // 创建克隆对象 var cloneObj = Array.isArray(obj) ? [] : {}; // 记录当前对象的克隆 hash.set(obj, cloneObj); // 递归拷贝对象属性 for (var key in obj) { if (copyContructor || Object.prototype.hasOwnProperty.call(obj, key)) { cloneObj[key] = deepClone(obj[key], hash, copyContructor); } } return cloneObj; } /** * 将日期格式化为中国日期格式。 * @param {string|Date|null|number} times - 要格式化的日期。如果为 null 或 undefined,则使用当前日期。 * @param {string} [fengefu='-'] - 用于格式化日期的分隔符。 * @returns {Object} 一个包含各种日期格式和组件的对象。 */ function chinaDate(times) { var fengefu = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '-'; if (times === null || times === undefined) { times = new Date(); } if (typeof times === 'string') { times = times.replace(/-/g, '/'); } fengefu = fengefu || '/'; var time = new Date(times); var nian = time.getFullYear(); var yue = ('00' + (time.getMonth() + 1)).slice(-2); var ri = ('00' + time.getDate()).slice(-2); var shi = ('00' + time.getHours()).slice(-2); var fen = ('00' + time.getMinutes()).slice(-2); var miao = ('00' + time.getSeconds()).slice(-2); var get0 = new Date(nian + '/' + yue + '/' + ri + ' 00:00:00').getTime(); var get59 = new Date(nian + '/' + yue + '/' + ri + ' 23:59:59').getTime(); return { fengefu: fengefu, newDate: time, nian: nian, yue: yue, ri: ri, shi: shi, fen: fen, miao: miao, date: nian + fengefu + yue + fengefu + ri + ' ' + shi + ':' + fen + ':' + miao, date0: nian + fengefu + yue + fengefu + ri + ' ' + '00:00:00', date59: nian + fengefu + yue + fengefu + ri + ' ' + '23:59:59', nyr: nian + fengefu + yue + fengefu + ri, sfm: shi + ':' + fen + ':' + miao, number: time.getTime(), get0: get0, get59: get59 }; } /** * 将 URL 参数解析为对象。 * @param {string} [url=window.location.href] - URL 字符串。如果未提供,则使用当前页面的 URL。 * @returns {Object} 一个包含解析后的 URL 参数的对象。 */ function getUrlParams() { var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.location.href; if (url.length === 0) { return {}; } else { var _url = decodeURIComponent(_url); var queryParams = _url.startsWith('?') ? _url.split('?')[1] : _url.split('?')[0]; var finallyData = {}; var vars = queryParams.length > 0 ? queryParams.split('&') : []; for (var i = 0; i < vars.length; i++) { var pair = vars[i].split('='); finallyData[pair[0]] = pair[1]; } return finallyData; } } /** * 通过创建一个锚点元素触发文件下载。 * @param {string} href - 要下载的文件的 URL。 * @param {string} [fileName=''] - 要下载的文件名。 */ function aDownLoad(href) { var fileName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; console.log(href, fileName); var aDownload = window.document.createElement('a'); aDownload.style.display = 'none'; aDownload.setAttribute('downLoad', fileName); aDownload.setAttribute('href', href); document.body.appendChild(aDownload); aDownload.click(); document.body.removeChild(aDownload); } /** * 从 Blob 响应中触发文件下载。 * @param {Blob} response - 要下载的 Blob 响应。 * @param {string} [fileName=''] - 要下载的文件名。 */ function aDownLoad2(response) { var fileName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; var blob = new Blob([response]); aDownLoad(URL.createObjectURL(blob), fileName); } /** * 检查对象中的某些或所有指定键是否有值。 * @param {Object} [obj={}] - 要检查的对象。 * @param {string[]} [keys=[]] - 要检查的键。 * @param {string} [type='some'] - 检查类型('some' 或 'all')。 * @returns {boolean} 如果条件满足,返回 `true`,否则返回 `false`。 */ var objKeysHasValue = exports.objKeysHasValue = function objKeysHasValue() { var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var keys = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'some'; if (type === 'some') { /*keys中的某一个是有值的*/ return keys.some(function (item, index) { return ![null, '', undefined].includes(obj[item]); }); } else { /*keys中的全部是有值的*/ return keys.every(function (item, index) { return ![null, '', undefined].includes(obj[item]); }); } }; // 增强型定时器管理模块 var anInterval = exports.anInterval = function () { var worker; var listeners = new Map(); var idCounter = 0; // 用于生成唯一ID function createWorker() { var script = "\n const intervals = new Map();\n onmessage = function(event) {\n const { command, id, time } = event.data;\n \n if (command === 'clear') {\n clearTimeout(intervals.get(id));\n intervals.delete(id);\n return;\n }\n\n if (intervals.has(id)) {\n clearTimeout(intervals.get(id));\n }\n \n function anIntervalF() {\n console.log('id',id);\n postMessage({ id });\n intervals.set(id, setTimeout(anIntervalF, time));\n }\n // \u4F7F\u7528 setTimeout \u5EF6\u8FDF\u7B2C\u4E00\u6B21\u6267\u884C\n intervals.set(id, setTimeout(anIntervalF, time));\n }\n "; var blob = new Blob([script], { type: 'text/javascript' }); var url = URL.createObjectURL(blob); worker = new Worker(url); worker.addEventListener('message', function (e) { var id = e.data.id; if (listeners.has(id)) { listeners.get(id).forEach(function (fn) { return fn(); }); } }); console.log('Worker 创建成功'); } function on(fn, time) { if (!worker) { createWorker(); } // 使用字符串ID代替Symbol var id = 'timer_' + idCounter++; if (!listeners.has(id)) { listeners.set(id, []); } listeners.get(id).push(fn); worker.postMessage({ id: id, time: time }); // console.log('定时器设置成功', id, time); return id; } function off(id) { if (listeners.has(id)) { var _worker; listeners["delete"](id); (_worker = worker) === null || _worker === void 0 || _worker.postMessage({ command: 'clear', id: id }); // console.log('定时器清除成功', id); } } return { on: on, off: off }; }(); var anTimeout = exports.anTimeout = function () { var worker; var listeners = new Map(); var idCounter = 0; // 用于生成唯一ID function createWorker() { var script = "\n const intervals = new Map();\n onmessage = function(event) {\n const { command, id, time } = event.data;\n \n if (command === 'clear') {\n clearTimeout(intervals.get(id));\n intervals.delete(id);\n return;\n }\n\n if (intervals.has(id)) {\n clearTimeout(intervals.get(id));\n }\n \n function anIntervalF() {\n console.log('id',id);\n postMessage({ id });\n }\n // \u4F7F\u7528 setTimeout \u5EF6\u8FDF\u7B2C\u4E00\u6B21\u6267\u884C\n intervals.set(id, setTimeout(anIntervalF, time));\n }\n "; var blob = new Blob([script], { type: 'text/javascript' }); var url = URL.createObjectURL(blob); worker = new Worker(url); worker.addEventListener('message', function (e) { var id = e.data.id; if (listeners.has(id)) { listeners.get(id).forEach(function (fn) { return fn(); }); } }); console.log('Worker 创建成功'); } function on(fn, time) { if (!worker) { createWorker(); } // 使用字符串ID代替Symbol var id = 'timer_' + idCounter++; if (!listeners.has(id)) { listeners.set(id, []); } listeners.get(id).push(fn); worker.postMessage({ id: id, time: time }); // console.log('定时器设置成功', id, time); return id; } function off(id) { if (listeners.has(id)) { var _worker2; listeners["delete"](id); (_worker2 = worker) === null || _worker2 === void 0 || _worker2.postMessage({ command: 'clear', id: id }); // console.log('定时器清除成功', id); } } return { on: on, off: off }; }(); var anWebSocket = exports.anWebSocket = /*#__PURE__*/function () { function anWebSocket(_ref) { var _this = this; var url = _ref.url, sendMessage = _ref.sendMessage, webSocketBack = _ref.webSocketBack, _ref$pingTimeout = _ref.pingTimeout, pingTimeout = _ref$pingTimeout === void 0 ? 5000 : _ref$pingTimeout, _ref$pongTimeout = _ref.pongTimeout, pongTimeout = _ref$pongTimeout === void 0 ? 4000 : _ref$pongTimeout, _ref$reconnectTimeout = _ref.reconnectTimeout, reconnectTimeout = _ref$reconnectTimeout === void 0 ? 4000 : _ref$reconnectTimeout, _ref$pingMsg = _ref.pingMsg, pingMsg = _ref$pingMsg === void 0 ? "heartbeat" : _ref$pingMsg, _ref$repeatLimit = _ref.repeatLimit, repeatLimit = _ref$repeatLimit === void 0 ? 3 : _ref$repeatLimit, _ref$showLog = _ref.showLog, showLog = _ref$showLog === void 0 ? false : _ref$showLog; _classCallCheck(this, anWebSocket); this.log = function () {}; this.error = function () {}; this.warn = function () {}; if (showLog === true) { this.log = function () { var _console; (_console = console).log.apply(_console, arguments); }; this.error = function () { var _console2; (_console2 = console).error.apply(_console2, arguments); }; this.warn = function () { var _console3; (_console3 = console).warn.apply(_console3, arguments); }; } console.log(showLog, this.log); if (!url) throw new Error("WebSocket URL is required"); this.opts = { url: url, sendMessage: sendMessage, webSocketBack: webSocketBack, pingTimeout: pingTimeout, pongTimeout: pongTimeout, reconnectTimeout: reconnectTimeout, pingMsg: pingMsg, repeatLimit: repeatLimit }; this.ws = null; this.repeat = 0; this.lockReconnect = false; this.forbidReconnect = false; console.log('this.forbidReconnect = false;'); this.pingTimeoutId = null; this.pongTimeoutId = null; this.activeConnections = 0; // 新增连接计数器 // 初始化事件处理器 this.onclose = function () { return _this.log("Connection closed"); }; this.onerror = function (e) { return _this.error("Error:", e); }; this.onopen = function () { return _this.handleOpen(); }; this.onmessage = function (e) { return _this.handleMessage(e); }; this.onreconnect = function () { return _this.log("Reconnecting (".concat(_this.repeat).concat(_this.opts.repeatLimit ? "/" + _this.opts.repeatLimit : "", ")")); }; this.createWebSocket(); } return _createClass(anWebSocket, [{ key: "createWebSocket", value: function createWebSocket() { try { if (!this.forbidReconnect && (!this.ws || this.ws.readyState === WebSocket.CLOSED)) { if (this.ws) { this.close(false); // 确保旧连接已关闭 this.ws = null; } this.ws = new WebSocket(this.opts.url); this.initEventHandle(); this.activeConnections++; // 增加连接计数器 } } catch (e) { this.error("创建ws连接失败:", e); if (!this.forbidReconnect) { this.log("创建ws连接失败,即将断线重连"); this.reconnect(); } } } }, { key: "initEventHandle", value: function initEventHandle() { var _this2 = this; this.ws.onclose = function (e) { _this2.onclose(e); console.log(3, e, 'asd', _this2.forbidReconnect); if (!_this2.forbidReconnect) { _this2.log("关闭了,即将断线重连"); _this2.reconnect(); } _this2.activeConnections--; // 减少连接计数器 }; this.ws.onerror = function (e) { _this2.onerror(e); if (!_this2.forbidReconnect) { _this2.log("onerror,即将断线重连"); _this2.reconnect(); } _this2.activeConnections--; // 减少连接计数器 }; this.ws.onopen = function () { _this2.repeat = 0; _this2.onopen(); _this2.heartCheck(); }; this.ws.onmessage = function (e) { _this2.onmessage(e); // 收到消息的时候重置心跳 _this2.heartCheck(); }; } }, { key: "send", value: function send(msg) { try { if (!this.isConnected()) { this.warn("连接失败"); return false; } var message; try { message = typeof msg === "string" ? msg : JSON.stringify(msg); } catch (e) { this.error("消息序列化失败:", e); return false; } this.ws.send(message); return true; } catch (e) { this.error("发送失败:", e); if (!this.forbidReconnect) { this.reconnect(); } return false; } } }, { key: "heartStart", value: function heartStart() { var _this3 = this; if (this.forbidReconnect) { return; } this.log("".concat(this.opts.pingTimeout, "\u6BEB\u79D2\u540E\u53D1\u9001\u5FC3\u8DF3")); this.pingTimeoutId = anInterval.on(function () { _this3.log("当前连接状态是否正常", _this3.isConnected()); if (_this3.isConnected()) { _this3.log("客户端-发送心跳"); _this3.ws.send(_this3.opts.pingMsg); _this3.pongTimeoutId = anInterval.on(function () { _this3.error("心跳超时,关闭连接(心跳发出后直到现在都未收到服务器的回复)"); _this3.ws.close(false); }, _this3.opts.pongTimeout); } }, this.opts.pingTimeout); } }, { key: "close", value: function close() { var permanently = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; // 如果permanently为true,则表示永久关闭,不再重连 if (permanently) { this.forbidReconnect = true; } this.heartReset(); if (this.ws) { // 临时存储当前WebSocket实例,避免在回调中引用this.ws var oldWs = this.ws; // 清除所有事件处理器,防止触发重连 oldWs.onclose = null; oldWs.onerror = null; oldWs.onopen = null; oldWs.onmessage = null; if ([WebSocket.OPEN, WebSocket.CONNECTING].includes(oldWs.readyState)) { oldWs.close(1000, "Normal closure"); } // 无论是否永久关闭,都清除当前WebSocket实例引用 this.ws = null; this.activeConnections--; // 减少连接计数器 } } }, { key: "reconnect", value: function reconnect() { var _this4 = this; if (this.forbidReconnect || this.shouldStopReconnect() || this.lockReconnect) { this.log("停止重连"); this.heartReset(); return; } ; this.lockReconnect = true; anTimeout.on(function () { if (_this4.forbidReconnect) return; _this4.log("重新连接..."); _this4.repeat++; _this4.createWebSocket(); // 重连完成后解锁 _this4.lockReconnect = false; }, this.opts.reconnectTimeout); } }, { key: "heartReset", value: function heartReset() { anInterval.off(this.pingTimeoutId); anInterval.off(this.pongTimeoutId); this.pingTimeoutId = null; this.pongTimeoutId = null; } }, { key: "heartCheck", value: function heartCheck() { this.log("心跳检测"); this.heartReset(); this.heartStart(); } // 添加一个新方法用于永久关闭连接 }, { key: "destroy", value: function destroy() { this.close(true); } // Helper methods }, { key: "shouldStopReconnect", value: function shouldStopReconnect() { return this.opts.repeatLimit > 0 && this.repeat >= this.opts.repeatLimit || this.lockReconnect || this.forbidReconnect; } }, { key: "handleOpen", value: function handleOpen() { this.log("连接成功"); if (this.opts.sendMessage && this.isConnected()) { this.ws.send(typeof this.opts.sendMessage === "string" ? this.opts.sendMessage : JSON.stringify(this.opts.sendMessage)); } } }, { key: "handleMessage", value: function handleMessage(event) { if (typeof this.opts.webSocketBack === "function") { this.opts.webSocketBack(event); } } // 公共接口 }, { key: "setEventHandlers", value: function setEventHandlers(handlers) { var _this5 = this; var validEvents = ["onopen", "onclose", "onerror", "onmessage", "onreconnect"]; validEvents.forEach(function (event) { if (handlers[event]) _this5[event] = handlers[event]; }); } }, { key: "getState", value: function getState() { var _this$ws$readyState, _this$ws; return (_this$ws$readyState = (_this$ws = this.ws) === null || _this$ws === void 0 ? void 0 : _this$ws.readyState) !== null && _this$ws$readyState !== void 0 ? _this$ws$readyState : WebSocket.CLOSED; } }, { key: "isConnected", value: function isConnected() { var _this$ws2; return ((_this$ws2 = this.ws) === null || _this$ws2 === void 0 ? void 0 : _this$ws2.readyState) === WebSocket.OPEN; } // 新增方法:获取当前的 WebSocket 连接数 }, { key: "getActiveConnections", value: function getActiveConnections() { return this.activeConnections; } }]); }(); // file转base64 function fileToBase64(file) { return new Promise(function (resolve, reject) { try { var reader = new FileReader(); reader.onloadend = function () { resolve(reader.result); }; reader.readAsDataURL(file); } catch (error) { reject(); } }); }