querystring: improve stringify() performance

PR-URL: https://github.com/nodejs/node/pull/33669
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
pull/33669/head
Brian White 2020-05-31 01:18:59 -04:00
parent 76ceaff270
commit 7b46793eee
No known key found for this signature in database
GPG Key ID: 606D7358F94DA209
3 changed files with 47 additions and 14 deletions

View File

@ -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],
});
@ -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];

View File

@ -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)

View File

@ -26,6 +26,7 @@
const {
Array,
ArrayIsArray,
MathAbs,
ObjectCreate,
ObjectKeys,
} = primordials;
@ -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 || '=';
@ -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);
@ -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)) {
@ -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)