| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- /**
- * json压缩工具
- */
- export default {
- /**
- * 压缩js对象成json字符串,并控制json字节大小,多余部分裁剪
- */
- compressObject(obj = {}, maxSize = 1024 * 10.24) {
- try {
- if (obj === undefined || obj === null) return obj;
- if (typeof obj == "string") {
- return this.truncateStrBySize(obj, maxSize);
- }
- if (typeof obj == "number") {
- return obj;
- }
- let t = new Date().getTime()
- const type = typeof obj;
- if (type === 'symbol') {
- obj = "Symbol->" + obj.toString();
- } else if (type === 'bigint') {
- obj = "bigint->" + obj.toString()
- } else if (typeof Error != "undefined" && obj instanceof Error) {
- obj = `Error->${obj.name}\n${obj.message}\n${obj.stack}`
- } else if (typeof Date != "undefined" && obj instanceof Date) {
- obj = "Date->" + obj.toISOString()
- } else if (typeof obj == "function") {
- obj = "Function->" + obj.toString()
- } else if (typeof RegExp != "undefined" && obj instanceof RegExp) {
- obj = "RegExp->" + obj.toString();
- } else if (typeof Map != "undefined" && obj instanceof Map) {
- obj = `Map->(${obj.size}) { ${Array.from(obj.entries()).map(([key, value]) => `${convertToString(key)} => ${convertToString(value)}`).join(', ')} }`;
- } else if (typeof Set != "undefined" && obj instanceof Set) {
- obj = `Set->(${obj.size}) { ${Array.from(obj.values()).map(value => convertToString(value)).join(', ')} }`;
- } else if (typeof Blob != "undefined" && obj instanceof Blob) {
- obj = `Blob->{ size: ${obj.size}, type: ${obj.type} }`;
- } else if (typeof File != "undefined" && obj instanceof File) {
- obj = `File->{ name: "${obj.name}", size: ${obj.size}, type: ${obj.type}, lastModified: ${new Date(obj.lastModified).toISOString()} }`;
- } else if (typeof URL != "undefined" && obj instanceof URL) {
- obj = `URL->{ href: "${obj.href}", protocol: "${obj.protocol}", host: "${obj.host}", pathname: "${obj.pathname}", search: "${obj.search}", hash: "${obj.hash}" }`;
- } else if (typeof FormData != "undefined" && obj instanceof FormData) {
- const entries = [];
- obj.forEach((key, item) => {
- entries.push(key)
- })
- obj = `FormData->{ ${entries.join(', ')} }`;
- } else if (typeof Location != "undefined" && obj instanceof Location) {
- obj = `Location->{ href: "${obj.href}", protocol: "${obj.protocol}", host: "${obj.host}", pathname: "${obj.pathname}", search: "${obj.search}", hash: "${obj.hash}" }`;
- } else if (typeof Document != "undefined" && obj instanceof Document) {
- obj = `Document->{ title: "${obj.title}", URL: "${obj.URL}" }`;
- } else if (typeof Window !== "undefined" && obj instanceof Window) {
- obj = `Window->{ location: ${this.compressObject(obj.location)}, document: ${this.compressObject(obj.document)} }`;
- } else if (typeof Element != "undefined" && obj instanceof Element) {
- obj = `Element->{ tagName: "${obj.tagName}", id: "${obj.id}", class: "${obj.className}" }`;
- } else if (typeof HTMLCanvasElement != "undefined" && obj instanceof HTMLCanvasElement) {
- obj = `Canvas->{ width: ${obj.width}, height: ${obj.height} }`;
- } else if (typeof HTMLAudioElement != "undefined" && obj instanceof HTMLAudioElement) {
- obj = `Audio->{ src: "${obj.src}", duration: ${obj.duration} }`;
- } else if (typeof HTMLVideoElement != "undefined" && obj instanceof HTMLVideoElement) {
- obj = `Video->{ src: "${obj.src}", width: ${obj.videoWidth}, height: ${obj.videoHeight}, duration: ${obj.duration} }`;
- } else if (typeof Storage != "undefined" && obj instanceof Storage) {
- obj = `Storage->{ length: ${obj.length} }`;
- }
- else if ((typeof Worker != "undefined" && typeof ServiceWorker != "undefined" && typeof SharedWorker != "undefined") && (obj instanceof Worker || obj instanceof ServiceWorker || obj instanceof SharedWorker)) {
- obj = `Worker->${obj.constructor.name} { scriptURL: "${obj.scriptURL}" }`;
- } else if (typeof WebSocket != "undefined" && obj instanceof WebSocket) {
- obj = `WebSocket->{ url: "${obj.url}", readyState: ${obj.readyState} }`;
- }
- else if (typeof XMLHttpRequest != "undefined" && obj instanceof XMLHttpRequest) {
- obj = `XMLHttpRequest->{ readyState: ${obj.readyState}, status: ${obj.status} }`;
- }
- else if (typeof EventSource != "undefined" && obj instanceof EventSource) {
- obj = `EventSource->{ url: "${obj.url}", readyState: ${obj.readyState} }`;
- }
- else if (typeof MediaStream != "undefined" && obj instanceof MediaStream) {
- obj = `MediaStream->{ id: "${obj.id}", active: ${obj.active} }`;
- }
- else if (typeof RTCPeerConnection != "undefined" && obj instanceof RTCPeerConnection) {
- obj = `RTCPeerConnection->{ connectionState: "${obj.connectionState}" }`;
- }
- else if (typeof AudioContext != "undefined" && obj instanceof AudioContext) {
- obj = `AudioContext->{ state: "${obj.state}" }`
- }
- else if (typeof Element != "undefined" && obj instanceof Element) {
- obj = `Element->{ tagName: "${obj.tagName}", id: "${obj.id}", class: "${obj.className}" }`
- }
- else if (typeof HTMLCanvasElement != "undefined" && obj instanceof HTMLCanvasElement) {
- obj = `Canvas->{ width: ${obj.width}, height: ${obj.height} }`
- }
- else if (typeof HTMLAudioElement != "undefined" && obj instanceof HTMLAudioElement) {
- obj = `Audio->{ src: "${obj.src}", duration: ${obj.duration} }`;
- }
- else if (typeof HTMLVideoElement != "undefined" && obj instanceof HTMLVideoElement) {
- obj = `Video->{ src: "${obj.src}", width: ${obj.videoWidth}, height: ${obj.videoHeight}, duration: ${obj.duration} }`;
- }
- else if (typeof Geolocation != "undefined" && obj instanceof Geolocation) {
- obj = `Geolocation->{ }`;
- }
- else if (typeof Performance != "undefined" && obj instanceof Performance) {
- obj = `Performance->{ now: ${obj.now()} }`
- }
- else if (typeof Event != "undefined" && obj instanceof Event) {
- obj = `Event->{ type: "${obj.type}", target: "${obj.target}" }`;
- }
- if (typeof obj == "string") {
- return this.truncateStrBySize(obj, maxSize);
- }
- if (typeof obj != "object") {
- return obj;
- }
- if (maxSize < 2) return {};
- let addEndOut = false;
- if (maxSize > 50) {
- let objSize = this.calculateStringByteSize(obj);
- if (objSize > maxSize) {
- maxSize = maxSize - 50;
- addEndOut = true;
- }
- }
- let sizeCount = 2;
- let str = this.safeJsonStringify(obj, (key, value) => {
- let keySize = this.calculateStringByteSize(key)
- if (typeof value == "object") {
- if (sizeCount + keySize + 6 > maxSize) {
- return;
- }
- sizeCount = sizeCount + keySize + 6;
- return value;
- }
- let valueSize = this.calculateStringByteSize(value)
- let rowSize = keySize + valueSize + 6;
- if (rowSize + sizeCount > maxSize) return;
- sizeCount = sizeCount + rowSize;
- return value;
- })
- let outPut = JSON.parse(str)
- if (addEndOut) {
- if (Array.isArray(outPut)) {
- outPut.push('(已截断其余部分)')
- } else if (typeof outPut == "object") {
- outPut["*注意"] = "(已截断其余部分)";
- }
- }
- // console.log("compressObject use time: " + (new Date().getTime() - t));
- return outPut;
- } catch (error) {
- console.log("compressObject error", error);
- return "";
- }
- },
- /**
- * 压缩数组不超过特定大小
- * @param {any[]} [arr=[]] 需要处理的数组
- * @param {string} [delType='start'] 数组超出后删除的开始位置
- * @param {number} [maxSize=1024 * 972] 数组最大字节数
- */
- compressArray(arr = [], delType = "start", maxSize = 1024 * 972) {
- let t = new Date().getTime()
- try {
- if (!arr || arr.length == 0 || !arr[0]) return [];
- let i = 0;
- while (true) {
- i = i + 1;
- if (i > 999999) return arr;
- if (!arr || arr.length == 0) {
- return [];
- }
- if (this.calculateStringByteSize(arr) <= maxSize) {
- // consoleLog("compressArray t=>" + (new Date().getTime() - t) + " i=>" + i)
- return arr;
- }
- if (delType == "start") {
- arr.splice(0, 1);
- } else {
- arr.splice(arr.length - 1, 1);
- }
- }
- } catch (error) {
- console.log("compressArray error", error);
- return [];
- }
- },
- /**
- * 计算对象或字符串占用的字节大小,传入对象将自动转json
- */
- calculateStringByteSize(str) {
- try {
- let type = typeof str;
- if (
- type == "bigint"
- || type == "number"
- || type == "boolean"
- ) {
- return str.toString().length;
- } else if (type == "function") {
- str = str.toString().length
- } else if (str === null || str === undefined) {
- return 0;
- } else {
- try {
- str = this.safeJsonStringify(str);
- if (str && str.hasOwnProperty) {
- return str.length;
- } else {
- return 1024 * 20;
- }
- } catch (error) {
- console.log("calculateStringByteSize error", error);
- return 1024 * 20;
- }
- }
- let size = 0;
- for (let i = 0; i < str.length; i++) {
- const charCode = str.charCodeAt(i);
- if (charCode < 0x0080) {
- size += 1;
- } else if (charCode < 0x0800) {
- size += 2;
- } else if (charCode >= 0xD800 && charCode <= 0xDFFF) {
- size += 4;
- i++;
- } else {
- size += 3;
- }
- }
- return size;
- } catch (error) {
- console.log("calculateStringByteSize error", error);
- return 1024 * 1024;
- }
- },
- /**
- * 安全的js对象转字符串
- */
- safeJsonStringify(obj, handleValue) {
- if (!obj) return "{}";
- try {
- if (handleValue) {
- return JSON.stringify(obj, (key, value) => {
- return handleValue(key, value)
- })
- } else {
- return JSON.stringify(obj, (key, value) => {
- return value;
- })
- }
- } catch (error) {
- // 尝试解析json失败,可能是变量循环引用的问题,继续尝试增加WeakSet解析
- }
- try {
- let seen = new WeakSet();
- let jsonStr = JSON.stringify(obj, (key, value) => {
- if (typeof value == "object") {
- try {
- if (value instanceof File) {
- value = "js:File";
- }
- if (value && value.constructor && value.constructor.name && typeof value.constructor.name == "string") {
- let className = value.constructor.name;
- if (className == "VueComponent") {
- return "js:Object:VueComponent";
- }
- }
- } catch (error) { }
- }
- if (typeof value == "function") {
- try {
- value = value.toString();
- } catch (error) {
- value = "js:function";
- }
- }
- if (typeof value === "object" && value !== null) {
- // 处理循环引用问题
- if (seen.has(value)) {
- return;
- }
- seen.add(value);
- }
- if (handleValue && typeof handleValue == "function") {
- try {
- return handleValue(key, value);
- } catch (error) {
- console.log("handleValue error", error);
- }
- return;
- }
- return value;
- });
- seen = null;
- return jsonStr;
- } catch (error) {
- return "{}";
- }
- },
- /**
- * 根据限制的字节大小截取字符串
- */
- truncateStrBySize(str = "", size = 20 * 1024) {
- try {
- if (size < 1) return "";
- if (this.calculateStringByteSize(str) <= size) return str;
- let endStr = "";
- if (size > 30) {
- endStr = "(已截断多余部分)"
- size = size - 30;
- }
- let low = 0, high = str.length, mid;
- while (low < high) {
- mid = Math.floor((low + high) / 2);
- let currentSize = this.calculateStringByteSize(str.substring(0, mid));
- if (currentSize > size) {
- // 如果大于限制值,减小高边界
- high = mid;
- } else {
- // 如果小于或等于限制值,增加低边界
- low = mid + 1;
- }
- }
- // 返回截断的字符串,注意low-1是因为low是最后一次检查超出大小时的位置
- return str.substring(0, low - 1) + endStr;
- } catch (error) {
- console.log("truncateStrBySize error", error);
- return "";
- }
- }
- }
|