Skip to content

Commit

Permalink
querystring: improve stringify() performance
Browse files Browse the repository at this point in the history
PR-URL: #33669
Reviewed-By: Benjamin Gruenbaum <[email protected]>
  • Loading branch information
mscdex authored and codebytere committed Jun 30, 2020
1 parent bce2bba commit c85bf0a
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 14 deletions.
9 changes: 7 additions & 2 deletions benchmark/querystring/querystring-stringify.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const common = require('../common.js');
const querystring = require('querystring');

const bench = common.createBenchmark(main, {
type: ['noencode', 'encodemany', 'encodelast', 'array'],
type: ['noencode', 'encodemany', 'encodelast', 'array', 'multiprimitives'],
n: [1e6],
});

Expand All @@ -28,7 +28,12 @@ function main({ type, n }) {
foo: [],
baz: ['bar'],
xyzzy: ['bar', 'quux', 'thud']
}
},
multiprimitives: {
foo: false,
bar: -13.37,
baz: '',
},
};
const input = inputs[type];

Expand Down
24 changes: 15 additions & 9 deletions lib/internal/querystring.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,25 @@ function encodeStr(str, noEscapeTable, hexTable) {

let out = '';
let lastPos = 0;
let i = 0;

for (let i = 0; i < len; i++) {
outer:
for (; i < len; i++) {
let c = str.charCodeAt(i);

// ASCII
if (c < 0x80) {
if (noEscapeTable[c] === 1)
continue;
if (lastPos < i)
out += str.slice(lastPos, i);
lastPos = i + 1;
out += hexTable[c];
continue;
while (c < 0x80) {
if (noEscapeTable[c] !== 1) {
if (lastPos < i)
out += str.slice(lastPos, i);
lastPos = i + 1;
out += hexTable[c];
}

if (++i === len)
break outer;

c = str.charCodeAt(i);
}

if (lastPos < i)
Expand Down
28 changes: 25 additions & 3 deletions lib/querystring.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
const {
Array,
ArrayIsArray,
MathAbs,
ObjectCreate,
ObjectKeys,
} = primordials;
Expand Down Expand Up @@ -162,6 +163,25 @@ function stringifyPrimitive(v) {
}


function encodeStringified(v, encode) {
if (typeof v === 'string')
return (v.length ? encode(v) : '');
if (typeof v === 'number' && isFinite(v)) {
// Values >= 1e21 automatically switch to scientific notation which requires
// escaping due to the inclusion of a '+' in the output
return (MathAbs(v) < 1e21 ? '' + v : encode('' + v));
}
if (typeof v === 'boolean')
return v ? 'true' : 'false';
return '';
}


function encodeStringifiedCustom(v, encode) {
return encode(stringifyPrimitive(v));
}


function stringify(obj, sep, eq, options) {
sep = sep || '&';
eq = eq || '=';
Expand All @@ -170,6 +190,8 @@ function stringify(obj, sep, eq, options) {
if (options && typeof options.encodeURIComponent === 'function') {
encode = options.encodeURIComponent;
}
const convert =
(encode === qsEscape ? encodeStringified : encodeStringifiedCustom);

if (obj !== null && typeof obj === 'object') {
const keys = ObjectKeys(obj);
Expand All @@ -179,7 +201,7 @@ function stringify(obj, sep, eq, options) {
for (let i = 0; i < len; ++i) {
const k = keys[i];
const v = obj[k];
let ks = encode(stringifyPrimitive(k));
let ks = convert(k, encode);
ks += eq;

if (ArrayIsArray(v)) {
Expand All @@ -188,13 +210,13 @@ function stringify(obj, sep, eq, options) {
const vlast = vlen - 1;
for (let j = 0; j < vlen; ++j) {
fields += ks;
fields += encode(stringifyPrimitive(v[j]));
fields += convert(v[j], encode);
if (j < vlast)
fields += sep;
}
} else {
fields += ks;
fields += encode(stringifyPrimitive(v));
fields += convert(v, encode);
}

if (i < flast)
Expand Down

0 comments on commit c85bf0a

Please sign in to comment.