an-function
Version:
js中常用的util方法;比如处理日期的函数,a连接下载,解析url,防抖,节流,基于webWork的定时器,websocket连接等等
612 lines (588 loc) • 21.7 kB
JavaScript
"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();
}
});
}