Fix: Performance improvements in Response-preview

- Replace jsonc-parser with custom JSON formatting in Response-preview
- JSON-Format only first 5MiB of response to prevent blocking render
- Add a missing useMemo in QueryResult

Co-authored-by: Pragadesh-45 <temporaryg7904@gmail.com>
This commit is contained in:
ramki-bruno
2025-03-20 13:48:21 +05:30
parent ccd4a14da6
commit 391348e3d3
3 changed files with 100 additions and 7 deletions

View File

@@ -80,7 +80,11 @@ const QueryResult = ({ item, collection, data, dataBuffer, width, disableRunEven
const contentType = getContentType(headers);
const mode = getCodeMirrorModeBasedOnContentType(contentType, data);
const [filter, setFilter] = useState(null);
const formattedData = formatResponse(data, dataBuffer, getEncoding(headers), mode, filter);
const responseEncoding = getEncoding(headers);
const formattedData = useMemo(
() => formatResponse(data, dataBuffer, responseEncoding, mode, filter),
[data, dataBuffer, responseEncoding, mode, filter]
);
const { displayedTheme } = useTheme();
const debouncedResultFilterOnChange = debounce((e) => {

View File

@@ -0,0 +1,83 @@
/**
* Credits to
* - https://github.com/zaach/jsonlint/blob/master/lib/formatter.js
* which is again copied from
* - https://github.com/umbrae/jsonlintdotcom/blob/master/c/js/jsl.format.js
* both under MIT license.
**/
/**
* Provide json reformatting in a character-by-character approach, so that even invalid JSON may be reformatted (to the best of its ability).
*
**/
export default function(json, indentChars) {
var i = 0,
il = 0,
tab = typeof indentChars !== 'undefined' ? indentChars : ' ',
newJson = '',
indentLevel = 0,
inString = false,
currentChar = null;
for (i = 0, il = json.length; i < il; i += 1) {
currentChar = json.charAt(i);
switch (currentChar) {
case '{':
case '[':
if (!inString) {
newJson += currentChar + '\n' + repeat(tab, indentLevel + 1);
indentLevel += 1;
} else {
newJson += currentChar;
}
break;
case '}':
case ']':
if (!inString) {
indentLevel -= 1;
newJson += '\n' + repeat(tab, indentLevel) + currentChar;
} else {
newJson += currentChar;
}
break;
case ',':
if (!inString) {
newJson += ',\n' + repeat(tab, indentLevel);
} else {
newJson += currentChar;
}
break;
case ':':
if (!inString) {
newJson += ': ';
} else {
newJson += currentChar;
}
break;
case ' ':
case '\n':
case '\t':
if (inString) {
newJson += currentChar;
}
break;
case '"':
if (i > 0 && json.charAt(i - 1) !== '\\') {
inString = !inString;
}
newJson += currentChar;
break;
default:
newJson += currentChar;
break;
}
}
return newJson;
}
function repeat(s, count) {
return new Array(count + 1).join(s);
}

View File

@@ -1,6 +1,7 @@
import { customAlphabet } from 'nanoid';
import xmlFormat from 'xml-formatter';
import { format as jsoncFormat, applyEdits as jsoncApplyEdits } from 'jsonc-parser';
import formatJson from 'utils/common/formatJson';
// a customized version of nanoid without using _ and -
export const uuid = () => {
@@ -28,11 +29,16 @@ export const waitForNextTick = () => {
};
export const prettifyJson = (doc) => {
return jsoncApplyEdits(
doc,
jsoncFormat(doc, null, {insertSpaces: true, tabSize: 2})
);
}
// Format only the first 5MiB of the doc/JSON-string,
// this is to prevent bigger responses from blocking the thread
// and making the UI unresponsive.
// TODO: Implement UI to allow users to format whole JSON on-demand
const maxFormatLegth = 1048576 * 5; // 2 ^ 20 * 5
const truncatedDoc = doc.substr(0, maxFormatLegth);
const restOfDoc = doc.substr(maxFormatLegth, doc.length);
const res = formatJson(truncatedDoc) + restOfDoc;
return res;
};
export const safeParseJSON = (str) => {
if (!str || !str.length || typeof str !== 'string') {